diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 52afc9c..d2c25e7 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,6 +1,5 @@
import { Routes, Route, Navigate } from "react-router-dom";
import { useAuth } from "./contexts/AuthContext";
-import { useContext } from 'react'
import Navbar from "./components/Navbar";
import Login from "./pages/login/Login";
import Signup from "./pages/Signup";
@@ -9,11 +8,11 @@ import Addresses from "./pages/addresses/Addresses";
import Alerts from "./pages/alerts/Alerts";
import AlertHistory from "./pages/alertHistory/AlertHistory";
import Account from "./pages/user_account/Account";
-import { AuthProvider } from "./ShopContext";
-import useAuth from "./ShopContext";
export default function App() {
- const { context } = useContext(ShopContext)
+ const { currentUser, isSubscribed, loading } = useAuth();
+
+ if (loading) return null;
if (!currentUser) {
return (
diff --git a/frontend/src/contexts/AuthContext.jsx b/frontend/src/contexts/AuthContext.jsx
index 47cc435..cb375e6 100644
--- a/frontend/src/contexts/AuthContext.jsx
+++ b/frontend/src/contexts/AuthContext.jsx
@@ -1,54 +1,94 @@
-import { createContext, useReducer, useContext } from "react";
-import shopReducer, { initialState } from "./shopReducer";
+import { createContext, useContext, useState, useEffect, useCallback } from "react";
+import {
+ onAuthStateChanged,
+ signInWithEmailAndPassword,
+ createUserWithEmailAndPassword,
+ signOut,
+} from "firebase/auth";
+import { auth } from "../firebase/config";
+import { getAccount } from "../api/account";
-const AuthContext = createContext(initialState);
+const AuthContext = createContext(undefined);
-export const AuthProvider = ({ children }) => {
- const [state, dispatch] = useReducer(shopReducer, initialState);
-
- const addAuthUser = (args) => {
- const updatedUser = state.user.concat(product);
- updatePrice(updatedCart);
- dispatch({
- type: "ADD_AUTH_USER",
- payload: {
- args: newUser
- }
- });
- };
-
- const logoutAuthUser = (args) => {
- const updatedUser = state.user.filter(
- (currentUser) => currentUser.name !== args.name
- );
- updateUser(updatedCart);
-
- dispatch({
- type: "REMOVE_AUTH_USER",
- payload: {
- args: updatedCart
- }
- });
- };
-
-
- const value = {
- authUser: state.name,
- authUserTier: state.tier,
- addAuthUser,
- logoutAuthUser
- };
- return {children};
+const DEFAULT_TIER_LIMITS = {
+ max_addresses: 1,
+ max_alert_types: 1,
+ allowed_channels: ["email"],
};
-const useAuth = () => {
- const context = useContext(ShopContext);
+export function AuthProvider({ children }) {
+ const [currentUser, setCurrentUser] = useState(null);
+ const [userTier, setUserTier] = useState("free");
+ const [tierLimits, setTierLimits] = useState(DEFAULT_TIER_LIMITS);
+ const [isSubscribed, setIsSubscribed] = useState(false);
+ const [loading, setLoading] = useState(true);
- if (context === undefined) {
- throw new Error("authUser must be used within AuthContext");
+ const fetchAccount = useCallback(async () => {
+ try {
+ const data = await getAccount();
+ setUserTier(data.subscription_tier || "free");
+ setTierLimits(data.tier_limits || DEFAULT_TIER_LIMITS);
+ setIsSubscribed(
+ data.subscription_status === "active" ||
+ data.subscription_status === "trialing",
+ );
+ } catch {
+ setUserTier("free");
+ setTierLimits(DEFAULT_TIER_LIMITS);
+ setIsSubscribed(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ const unsubscribe = onAuthStateChanged(auth, async (user) => {
+ setCurrentUser(user);
+ if (user) {
+ await fetchAccount();
+ } else {
+ setUserTier("free");
+ setTierLimits(DEFAULT_TIER_LIMITS);
+ setIsSubscribed(false);
+ }
+ setLoading(false);
+ });
+ return unsubscribe;
+ }, [fetchAccount]);
+
+ async function signup(email, password) {
+ const cred = await createUserWithEmailAndPassword(auth, email, password);
+ return cred.user;
}
+ async function login(email, password) {
+ const cred = await signInWithEmailAndPassword(auth, email, password);
+ return cred.user;
+ }
+
+ async function logout() {
+ await signOut(auth);
+ }
+
+ const value = {
+ currentUser,
+ userTier,
+ tierLimits,
+ isSubscribed,
+ loading,
+ signup,
+ login,
+ logout,
+ refreshAccount: fetchAccount,
+ };
+
+ return {children};
+}
+
+export function useAuth() {
+ const context = useContext(AuthContext);
+ if (context === undefined) {
+ throw new Error("useAuth must be used within an AuthProvider");
+ }
return context;
-};
+}
export default useAuth;
diff --git a/frontend/src/contexts/UserPropertiesContext.jsx b/frontend/src/contexts/UserPropertiesContext.jsx
new file mode 100644
index 0000000..0bb91a4
--- /dev/null
+++ b/frontend/src/contexts/UserPropertiesContext.jsx
@@ -0,0 +1,44 @@
+import { createContext, useReducer, useContext } from "react";
+
+const initialState = {
+ email: "",
+ password: "",
+};
+
+const ACTION_TYPES = {
+ SET_USER_PROPERTIES: "SET_USER_PROPERTIES",
+ CLEAR_USER_PROPERTIES: "CLEAR_USER_PROPERTIES",
+};
+
+function userPropertiesReducer(state, action) {
+ switch (action.type) {
+ case ACTION_TYPES.SET_USER_PROPERTIES:
+ return { ...state, ...action.payload };
+ case ACTION_TYPES.CLEAR_USER_PROPERTIES:
+ return { ...initialState };
+ default:
+ return state;
+ }
+}
+
+const UserPropertiesContext = createContext(undefined);
+
+export function UserPropertiesProvider({ children }) {
+ const [state, dispatch] = useReducer(userPropertiesReducer, initialState);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useUserProperties() {
+ const context = useContext(UserPropertiesContext);
+ if (context === undefined) {
+ throw new Error(
+ "useUserProperties must be used within a UserPropertiesProvider",
+ );
+ }
+ return context;
+}
diff --git a/frontend/src/pages/subscribe/Subscribe.jsx b/frontend/src/pages/subscribe/Subscribe.jsx
index 98e44e7..7a9560a 100644
--- a/frontend/src/pages/subscribe/Subscribe.jsx
+++ b/frontend/src/pages/subscribe/Subscribe.jsx
@@ -141,6 +141,8 @@ export default function Subscribe() {
return;
}
+ sessionStorage.setItem("kp_onboard_email", data.email);
+ sessionStorage.setItem("kp_onboard_pw", data.password);
dispatch({
type: ACTION_TYPES.SET_USER_PROPERTIES,
payload: { email: data.email, password: data.password },
diff --git a/frontend/src/reducers/authReducer.jsx b/frontend/src/reducers/authReducer.jsx
deleted file mode 100644
index dd1c505..0000000
--- a/frontend/src/reducers/authReducer.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { useReducer } from "react"
-
-const UserAuthContext = createContext();
-
-export const initialState = {
- authUser: null,
- AuthTier: null
-};
-
-const authReducer = (state, action) => {
- const { type, payload = "FREE_TIER" } = action
-
- switch (type) {
- case "ADD_AUTH_USER":
- console.log("ADD_AUTH_USER", payload);
- return {
- ...state,
- auth: payload
- };
- default:
- throw new Error(`No case for type ${type} found.`);
- }
- switch (type) {
- case "DELETE_AUTH_USER":
- return {
- ...state,
- users: state.users.filter(user => user.id !== action.userIdToDelete)
- };
- }
-}
-
-export default shopReducer
\ No newline at end of file