diff --git a/backend/README.md b/backend/README.md
index 940937f..9d3d3b8 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -1,4 +1,5 @@
-Backend startup quickstarat:
+Backend startup quickstart:
+
-----------------------------> BEST
## 1. brew services start postgresql@15
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 47fb0d3..52afc9c 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,5 +1,6 @@
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";
@@ -8,9 +9,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 { currentUser, isSubscribed } = useAuth();
+ const { context } = useContext(ShopContext)
if (!currentUser) {
return (
diff --git a/frontend/src/contexts/AuthContext.jsx b/frontend/src/contexts/AuthContext.jsx
index 0413bd3..47cc435 100644
--- a/frontend/src/contexts/AuthContext.jsx
+++ b/frontend/src/contexts/AuthContext.jsx
@@ -1,140 +1,54 @@
-/**
- * AuthContext - Firebase Authentication State Management
- *
- * Provides authentication state, tier info, and methods throughout the app
- */
+import { createContext, useReducer, useContext } from "react";
+import shopReducer, { initialState } from "./shopReducer";
-import { createContext, useContext, useEffect, useState, useCallback } from "react";
-import {
- createUserWithEmailAndPassword,
- signInWithEmailAndPassword,
- signOut,
- onAuthStateChanged,
-} from "firebase/auth";
-import { auth } from "../firebase/config";
-import { getAccount } from "../api/account";
+const AuthContext = createContext(initialState);
-const AuthContext = createContext();
+export const AuthProvider = ({ children }) => {
+ const [state, dispatch] = useReducer(shopReducer, initialState);
-const DEFAULT_TIER_LIMITS = {
- max_addresses: 1,
- max_alert_types: 1,
- allowed_channels: ["email"],
+ 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};
};
-/**
- * Hook to access auth context
- * @returns {Object} Auth context value
- */
-export function useAuth() {
- const context = useContext(AuthContext);
- if (!context) {
- throw new Error("useAuth must be used within AuthProvider");
- }
- return context;
-}
+const useAuth = () => {
+ const context = useContext(ShopContext);
-/**
- * AuthProvider - Wraps app and provides auth state + tier info
- */
-export function AuthProvider({ children }) {
- const [currentUser, setCurrentUser] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+ if (context === undefined) {
+ throw new Error("authUser must be used within AuthContext");
+ }
- const [userTier, setUserTier] = useState("free");
- const [tierLimits, setTierLimits] = useState(DEFAULT_TIER_LIMITS);
- const [addressCount, setAddressCount] = useState(0);
- const [subscriptionStatus, setSubscriptionStatus] = useState("none");
+ return context;
+};
- const refreshAccount = useCallback(async () => {
- try {
- const data = await getAccount();
- setUserTier(data.subscription_tier || "free");
- setTierLimits(data.tier_limits || DEFAULT_TIER_LIMITS);
- setAddressCount(data.address_count || 0);
- setSubscriptionStatus(data.subscription_status || "none");
- } catch {
- // account fetch can fail during onboarding before subscription is active
- }
- }, []);
-
- async function signup(email, password) {
- try {
- setError(null);
- const result = await createUserWithEmailAndPassword(
- auth,
- email,
- password,
- );
- return result.user;
- } catch (err) {
- setError(err.message);
- throw err;
- }
- }
-
- async function login(email, password) {
- try {
- setError(null);
- const result = await signInWithEmailAndPassword(
- auth,
- email,
- password,
- );
- return result.user;
- } catch (err) {
- setError(err.message);
- throw err;
- }
- }
-
- async function logout() {
- try {
- setError(null);
- setUserTier("free");
- setTierLimits(DEFAULT_TIER_LIMITS);
- setAddressCount(0);
- setSubscriptionStatus("none");
- await signOut(auth);
- } catch (err) {
- setError(err.message);
- throw err;
- }
- }
-
- useEffect(() => {
- const unsubscribe = onAuthStateChanged(auth, (user) => {
- setCurrentUser(user);
- setLoading(false);
- if (user) {
- refreshAccount();
- }
- });
- return unsubscribe;
- }, [refreshAccount]);
-
- const isSubscribed =
- subscriptionStatus === "active" || subscriptionStatus === "trialing";
-
- const value = {
- currentUser,
- signup,
- login,
- logout,
- error,
- loading,
- userTier,
- tierLimits,
- addressCount,
- subscriptionStatus,
- isSubscribed,
- refreshAccount,
- };
-
- return (
-
- {!loading && children}
-
- );
-}
+export default useAuth;
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index 00913df..6c791fd 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -2,15 +2,18 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./contexts/AuthContext";
+import { UserPropertiesProvider } from "./contexts/UserPropertiesContext";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")).render(
-
-
-
+
+
+
+
+
,
);
diff --git a/frontend/src/pages/subscribe/Subscribe.jsx b/frontend/src/pages/subscribe/Subscribe.jsx
index fc3c3ca..98e44e7 100644
--- a/frontend/src/pages/subscribe/Subscribe.jsx
+++ b/frontend/src/pages/subscribe/Subscribe.jsx
@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useAuth } from "../../contexts/AuthContext";
+import { useUserProperties } from "../../contexts/UserPropertiesContext";
import {
createOnboardingCheckout,
verifyCheckoutSession,
@@ -15,6 +16,7 @@ const STEPS = ["Create Account", "Choose Plan"];
export default function Subscribe() {
const { currentUser, signup } = useAuth();
+ const { state: userProps, dispatch, ACTION_TYPES } = useUserProperties();
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
@@ -89,9 +91,7 @@ export default function Subscribe() {
// Phase 2: authenticated — verify the checkout and go to the dashboard.
setSearchParams({}, { replace: true });
setLoading(true);
- if (signupLockKey) sessionStorage.removeItem(signupLockKey);
- sessionStorage.removeItem("kp_onboard_email");
- sessionStorage.removeItem("kp_onboard_pw");
+ dispatch({ type: ACTION_TYPES.CLEAR_USER_PROPERTIES });
verifyCheckoutSession(sessionId)
.then(() => {
@@ -102,7 +102,7 @@ export default function Subscribe() {
setStep(2);
})
.finally(() => setLoading(false));
- }, [currentUser, searchParams, setSearchParams, signup, navigate]);
+ }, [currentUser, searchParams, setSearchParams, signup, navigate, userProps, dispatch, ACTION_TYPES]);
// ── Step handlers ─────────────────────────────────────────────────────────
@@ -141,8 +141,10 @@ 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 },
+ });
const { url } = await createOnboardingCheckout(
data.email,
data.selectedTier,
diff --git a/frontend/src/reducers/authReducer.jsx b/frontend/src/reducers/authReducer.jsx
new file mode 100644
index 0000000..dd1c505
--- /dev/null
+++ b/frontend/src/reducers/authReducer.jsx
@@ -0,0 +1,32 @@
+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