Skip to content

Commit

Permalink
Created AuthContext to share current login user's info
Browse files Browse the repository at this point in the history
  • Loading branch information
TPH777 committed Jul 10, 2024
1 parent 2f873ee commit 4922be3
Show file tree
Hide file tree
Showing 13 changed files with 600 additions and 143 deletions.
418 changes: 384 additions & 34 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"preview": "vite preview"
},
"dependencies": {
"@anatoliygatt/heart-switch": "^1.0.13",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"bootstrap": "^5.3.3",
"firebase": "^10.12.2",
"react": "^18.2.0",
Expand Down
25 changes: 14 additions & 11 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import { Layout } from "./Layout";
import { RegisterPage } from "./pages/Register";
import { Dashboard } from "./pages/Dashboard";
import { FavoritePage } from "./pages/Favorites";
import { AuthContextProvider } from "./context/Auth";

function App() {
return (
<Router>
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/register" element={<RegisterPage />} />
<Route path="/favorites" element={<FavoritePage />} />
</Route>
</Routes>
</Router>
<AuthContextProvider>
<Router>
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/register" element={<RegisterPage />} />
<Route path="/favorites" element={<FavoritePage />} />
</Route>
</Routes>
</Router>
</AuthContextProvider>
);
}

Expand Down
19 changes: 10 additions & 9 deletions src/components/Add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { getDownloadURL, ref, uploadBytes } from "firebase/storage";
import { v4 as uuidv4 } from "uuid";
import { addSuccess, invalidInputWarning } from "../functions/Alert";
import { CrudForm } from "./CrudForm";
import { useAuth } from "../context/Auth";

interface AddProps {
user: any;
getFoodList: Function;
setIsAdding: React.Dispatch<React.SetStateAction<boolean>>;
}

export const Add = ({ user, getFoodList, setIsAdding }: AddProps) => {
export const Add = ({ getFoodList, setIsAdding }: AddProps) => {
const user = useAuth().user;
const [name, setName] = useState<string>("");
const [price, setPrice] = useState<number>(0);
const [image, setImage] = useState<any>();
Expand All @@ -34,7 +35,7 @@ export const Add = ({ user, getFoodList, setIsAdding }: AddProps) => {
}

// Upload image to storage
const imagePath = "images/" + `${user.uid}/` + uuidv4();
const imagePath = "images/" + `${user?.uid}/` + uuidv4();
const storageRef = ref(storage, imagePath);
try {
await uploadBytes(storageRef, image);
Expand All @@ -43,19 +44,19 @@ export const Add = ({ user, getFoodList, setIsAdding }: AddProps) => {
}

getDownloadURL(storageRef) // Download image url
.then(async (url) => {
const imageURL = url;
await addDoc(collection(db, "food"), {
.then(async (imageURL) => {
const newFood = {
name: name,
price: price,
date: date,
post: post,
userId: user.uid,
business: user.displayName,
userId: user?.uid,
business: user?.displayName,
imageURL: imageURL,
imagePath: imagePath,
cuisine: cuisine,
});
};
await addDoc(collection(db, "food"), newFood);
setIsAdding(false);
getFoodList();
addSuccess(name, price);
Expand Down
6 changes: 3 additions & 3 deletions src/components/Cards.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { Badge, Button, Card, Col, Row } from "react-bootstrap";
import { FoodItem } from "../interface/FoodItem";
import { timestampToString } from "../functions/Date";
import { useAuth } from "../context/Auth";

export const Cards = ({
user,
foodList,
updateFood,
deleteFood,
}: {
user: any;
foodList: FoodItem[];
updateFood: Function;
deleteFood: Function;
}) => {
const user = useAuth().user;
return (
<>
{foodList && foodList.length > 0 ? (
<Row md={4} className="g-4">
{foodList.map(
(food, index) =>
food.userId == user.uid && (
food.userId == user?.uid && (
<Col key={index}>
<Card
className="flex"
Expand Down
26 changes: 4 additions & 22 deletions src/components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
import { User, onAuthStateChanged, signOut } from "firebase/auth";
import { signOut } from "firebase/auth";
import { useNavigate } from "react-router-dom";
import { auth, db } from "../config/firebase";
import { useEffect, useState } from "react";
import { auth } from "../config/firebase";
import { Button, Container, Nav, Navbar } from "react-bootstrap";
import { doc } from "firebase/firestore";
import { useAuth } from "../context/Auth";

export function NavBar() {
let navigate = useNavigate();
const [user, setUser] = useState<User>();
const [isConsumer, setIsConsumer] = useState<boolean>(false);

const getUser = async () => {
onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
if (doc(db, "consumer", user.uid)) {
// Consumer account
setIsConsumer(true);
}
}
});
};

useEffect(() => {
getUser();
}, []);
const { user, isConsumer } = useAuth();

const Logout = () => {
signOut(auth)
Expand Down
72 changes: 72 additions & 0 deletions src/context/Auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
useContext,
createContext,
useEffect,
useState,
FC,
ReactNode,
} from "react";
import { onAuthStateChanged, User } from "firebase/auth";
import { auth, db } from "../config/firebase";
import { doc, getDoc } from "firebase/firestore";

// Define the type for the UserContext
type UserContextType = {
user: User | null;
isConsumer: boolean;
};

// Create a context with a default value of null
const AuthContext = createContext<UserContextType | null>(null);

// AuthContextProvider component to wrap around the app
export const AuthContextProvider: FC<{ children: ReactNode }> = ({
children,
}) => {
const [user, setUser] = useState<User | null>(null);
const [isConsumer, setIsConsumer] = useState<boolean>(false);

// useEffect to listen for authentication state changes
useEffect(() => {
const unsubscribe = onAuthStateChanged(
auth,
async (currentUser) => {
setUser(currentUser); // Set the current user in state
if (currentUser) {
const docRef = doc(db, "consumer", currentUser.uid);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
setIsConsumer(true);
}
}
},
(error) => {
console.error("Auth state change error: ", error); // Log any errors
}
);

// Cleanup subscription on component unmount
return () => {
unsubscribe();
};
}, []);

// Provide the user state to child components
return (
<AuthContext.Provider value={{ user, isConsumer }}>
{children}
</AuthContext.Provider>
);
};

// Custom hook to use the AuthContext
export const useAuth = (): UserContextType => {
const context = useContext(AuthContext);

// Throw an error if the hook is used outside of AuthProvider
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}

return context; // Return the context value
};
21 changes: 11 additions & 10 deletions src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { auth, db } from "../config/firebase";
import { db } from "../config/firebase";
import { doc, deleteDoc, getDoc } from "firebase/firestore";
import { Cards } from "../components/Cards";
import { Edit } from "../components/Edit";
Expand All @@ -10,9 +10,16 @@ import { FoodItem } from "../interface/FoodItem";
import { deleteSuccess, deleteWarning } from "../functions/Alert";
import { getFoodList } from "../functions/GetFood";
import { Spinner } from "react-bootstrap";
import { useAuth } from "../context/Auth";
import { useNavigate } from "react-router-dom";

export function Dashboard() {
const user = auth.currentUser;
const user = useAuth().user;
let navigate = useNavigate();
if (!user) {
navigate("/login");
}

const [isAdding, setIsAdding] = useState<boolean>(false);
const [selectedFoodId, setSelectedFoodId] = useState<string>("");
const [isEditing, setIsEditing] = useState<boolean>(false);
Expand All @@ -26,8 +33,7 @@ export function Dashboard() {
const fetchFoodList = async () => {
try {
setIsLoading(true);
const updatedFoodList = await getFoodList();
setFoodList(updatedFoodList);
setFoodList(await getFoodList());
setIsLoading(false);
} catch (error) {
console.error("Error fetching food items:", error);
Expand Down Expand Up @@ -109,7 +115,6 @@ export function Dashboard() {
/>

<Cards
user={user}
foodList={searchFoodList}
updateFood={updateFood}
deleteFood={deleteFood}
Expand All @@ -118,11 +123,7 @@ export function Dashboard() {
)}

{isAdding && (
<Add
user={user}
getFoodList={fetchFoodList}
setIsAdding={setIsAdding}
/>
<Add getFoodList={fetchFoodList} setIsAdding={setIsAdding} />
)}

{isEditing && (
Expand Down
16 changes: 9 additions & 7 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Search } from "../components/Search";
import { FoodItem } from "../interface/FoodItem";
import { timestampToString } from "../functions/Date";
import { getFoodList } from "../functions/GetFood";
// import { HeartSwitch } from "@anatoliygatt/heart-switch";

export function Home() {
const [foodList, setFoodList] = useState<FoodItem[]>([]);
Expand All @@ -19,8 +20,7 @@ export function Home() {
setIsLoading(true);
const updatedFoodList = await getFoodList();
const postedFoodList = updatedFoodList.filter((food) => {
// Display posted food items only
return food.post === true;
return food.post === true; // Display posted food items only
});
setFoodList(postedFoodList);
setIsLoading(false);
Expand Down Expand Up @@ -88,11 +88,7 @@ export function Home() {
<Card.Body>
<Card.Title>{food.name}</Card.Title>
<Card.Subtitle>${food.price}</Card.Subtitle>
<Card.Text>
{food.date
? `Date: ${timestampToString(food.date)}`
: "No Date"}
</Card.Text>
<Card.Text>Date: ${timestampToString(food.date)}</Card.Text>
<Badge
style={{ cursor: "pointer" }}
pill
Expand All @@ -111,6 +107,12 @@ export function Home() {
>
{food.business}
</Badge>
{/* <HeartSwitch
checked={checkedFav}
onChange={(event) => {
handleFavChange(event.target.checked, food.id)
}}
/> */}
</Card.Body>
</Card>
</Col>
Expand Down
1 change: 1 addition & 0 deletions src/pages/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const LoginPage = () => {
setAuthenticating(true);
try {
await signInWithEmailAndPassword(auth, email, password);
navigate("/dashboard");
} catch (error) {
setAuthenticating(false);
setError(getErrorMessage(error));
Expand Down
Loading

0 comments on commit 4922be3

Please sign in to comment.