This commit is contained in:
KS Jannette
2026-03-29 16:21:48 -04:00
parent 06d7cd4169
commit 0f770742ef
5 changed files with 133 additions and 80 deletions

View File

@@ -1,6 +1,5 @@
import { Routes, Route, Navigate } from "react-router-dom"; import { Routes, Route, Navigate } from "react-router-dom";
import { useAuth } from "./contexts/AuthContext"; import { useAuth } from "./contexts/AuthContext";
import { useContext } from 'react'
import Navbar from "./components/Navbar"; import Navbar from "./components/Navbar";
import Login from "./pages/login/Login"; import Login from "./pages/login/Login";
import Signup from "./pages/Signup"; import Signup from "./pages/Signup";
@@ -9,11 +8,11 @@ import Addresses from "./pages/addresses/Addresses";
import Alerts from "./pages/alerts/Alerts"; import Alerts from "./pages/alerts/Alerts";
import AlertHistory from "./pages/alertHistory/AlertHistory"; import AlertHistory from "./pages/alertHistory/AlertHistory";
import Account from "./pages/user_account/Account"; import Account from "./pages/user_account/Account";
import { AuthProvider } from "./ShopContext";
import useAuth from "./ShopContext";
export default function App() { export default function App() {
const { context } = useContext(ShopContext) const { currentUser, isSubscribed, loading } = useAuth();
if (loading) return null;
if (!currentUser) { if (!currentUser) {
return ( return (

View File

@@ -1,54 +1,94 @@
import { createContext, useReducer, useContext } from "react"; import { createContext, useContext, useState, useEffect, useCallback } from "react";
import shopReducer, { initialState } from "./shopReducer"; 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 DEFAULT_TIER_LIMITS = {
const [state, dispatch] = useReducer(shopReducer, initialState); max_addresses: 1,
max_alert_types: 1,
const addAuthUser = (args) => { allowed_channels: ["email"],
const updatedUser = state.user.concat(product);
updatePrice(updatedCart);
dispatch({
type: "ADD_AUTH_USER",
payload: {
args: newUser
}
});
}; };
const logoutAuthUser = (args) => { export function AuthProvider({ children }) {
const updatedUser = state.user.filter( const [currentUser, setCurrentUser] = useState(null);
(currentUser) => currentUser.name !== args.name const [userTier, setUserTier] = useState("free");
const [tierLimits, setTierLimits] = useState(DEFAULT_TIER_LIMITS);
const [isSubscribed, setIsSubscribed] = useState(false);
const [loading, setLoading] = useState(true);
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",
); );
updateUser(updatedCart); } catch {
setUserTier("free");
dispatch({ setTierLimits(DEFAULT_TIER_LIMITS);
type: "REMOVE_AUTH_USER", setIsSubscribed(false);
payload: {
args: updatedCart
} }
}); }, []);
};
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 = { const value = {
authUser: state.name, currentUser,
authUserTier: state.tier, userTier,
addAuthUser, tierLimits,
logoutAuthUser isSubscribed,
loading,
signup,
login,
logout,
refreshAccount: fetchAccount,
}; };
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
const useAuth = () => {
const context = useContext(ShopContext);
if (context === undefined) {
throw new Error("authUser must be used within AuthContext");
} }
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context; return context;
}; }
export default useAuth; export default useAuth;

View File

@@ -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 (
<UserPropertiesContext.Provider value={{ state, dispatch, ACTION_TYPES }}>
{children}
</UserPropertiesContext.Provider>
);
}
export function useUserProperties() {
const context = useContext(UserPropertiesContext);
if (context === undefined) {
throw new Error(
"useUserProperties must be used within a UserPropertiesProvider",
);
}
return context;
}

View File

@@ -141,6 +141,8 @@ export default function Subscribe() {
return; return;
} }
sessionStorage.setItem("kp_onboard_email", data.email);
sessionStorage.setItem("kp_onboard_pw", data.password);
dispatch({ dispatch({
type: ACTION_TYPES.SET_USER_PROPERTIES, type: ACTION_TYPES.SET_USER_PROPERTIES,
payload: { email: data.email, password: data.password }, payload: { email: data.email, password: data.password },

View File

@@ -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