Convert frontend from Git submodule to a regular monorepo directory for simplified development workflow. Changes: - Remove frontend submodule tracking (mode 160000 gitlink) - Add all frontend source files directly to main repository - Remove frontend/.git directory - Update CLAUDE.md to clarify true monorepo structure - Update Frontend Architecture documentation (React Router v6, Socket.IO, Leaflet, ErrorBoundary) Benefits of Monorepo: - Single git clone for entire project - Unified commit history - Simpler CI/CD pipeline - Easier for new developers - No submodule sync issues - Atomic commits across frontend and backend Frontend Files Added: - All React components (MapView, ErrorBoundary, TaskList, SocialFeed, etc.) - Context providers (AuthContext, SocketContext) - Complete test suite with MSW - Dependencies and configuration files Branch Cleanup: - Using 'main' as default branch (develop deleted) - Frontend no longer has separate Git history 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
144 lines
4.2 KiB
JavaScript
144 lines
4.2 KiB
JavaScript
import React, { createContext, useState, useEffect } from "react";
|
|
import axios from "axios";
|
|
import { toast } from "react-toastify";
|
|
|
|
export const AuthContext = createContext();
|
|
|
|
const AuthProvider = ({ children }) => {
|
|
const [auth, setAuth] = useState({
|
|
token: null,
|
|
isAuthenticated: false,
|
|
user: null,
|
|
loading: true,
|
|
});
|
|
|
|
useEffect(() => {
|
|
const loadUser = async () => {
|
|
const token = localStorage.getItem("token");
|
|
if (token) {
|
|
axios.defaults.headers.common["x-auth-token"] = token;
|
|
try {
|
|
const res = await axios.get("/api/auth");
|
|
setAuth({
|
|
token,
|
|
isAuthenticated: true,
|
|
user: res.data,
|
|
loading: false,
|
|
});
|
|
} catch (error) {
|
|
console.error("Failed to load user:", error);
|
|
localStorage.removeItem("token");
|
|
delete axios.defaults.headers.common["x-auth-token"];
|
|
setAuth({
|
|
token: null,
|
|
isAuthenticated: false,
|
|
user: null,
|
|
loading: false,
|
|
});
|
|
}
|
|
} else {
|
|
setAuth({
|
|
token: null,
|
|
isAuthenticated: false,
|
|
user: null,
|
|
loading: false,
|
|
});
|
|
}
|
|
};
|
|
|
|
loadUser();
|
|
}, []);
|
|
|
|
const login = async (email, password) => {
|
|
try {
|
|
const res = await axios.post("/api/auth/login", { email, password });
|
|
localStorage.setItem("token", res.data.token);
|
|
axios.defaults.headers.common["x-auth-token"] = res.data.token;
|
|
|
|
try {
|
|
const userRes = await axios.get("/api/auth");
|
|
setAuth({
|
|
token: res.data.token,
|
|
isAuthenticated: true,
|
|
user: userRes.data,
|
|
loading: false,
|
|
});
|
|
toast.success("Login successful!");
|
|
return { success: true };
|
|
} catch (userError) {
|
|
console.error("Failed to fetch user after login:", userError);
|
|
localStorage.removeItem("token");
|
|
delete axios.defaults.headers.common["x-auth-token"];
|
|
toast.error("Login succeeded but failed to load user data");
|
|
return { success: false, error: "Failed to load user data" };
|
|
}
|
|
} catch (error) {
|
|
console.error("Login error:", error);
|
|
const errorMessage =
|
|
error.response?.data?.msg ||
|
|
error.response?.data?.message ||
|
|
"Login failed. Please check your credentials.";
|
|
toast.error(errorMessage);
|
|
return { success: false, error: errorMessage };
|
|
}
|
|
};
|
|
|
|
const register = async (name, email, password) => {
|
|
try {
|
|
const res = await axios.post("/api/auth/register", {
|
|
name,
|
|
email,
|
|
password,
|
|
});
|
|
localStorage.setItem("token", res.data.token);
|
|
axios.defaults.headers.common["x-auth-token"] = res.data.token;
|
|
|
|
try {
|
|
const userRes = await axios.get("/api/auth");
|
|
setAuth({
|
|
token: res.data.token,
|
|
isAuthenticated: true,
|
|
user: userRes.data,
|
|
loading: false,
|
|
});
|
|
toast.success("Registration successful! Welcome aboard!");
|
|
return { success: true };
|
|
} catch (userError) {
|
|
console.error("Failed to fetch user after registration:", userError);
|
|
localStorage.removeItem("token");
|
|
delete axios.defaults.headers.common["x-auth-token"];
|
|
toast.error("Registration succeeded but failed to load user data");
|
|
return { success: false, error: "Failed to load user data" };
|
|
}
|
|
} catch (error) {
|
|
console.error("Registration error:", error);
|
|
const errorMessage =
|
|
error.response?.data?.msg ||
|
|
error.response?.data?.message ||
|
|
"Registration failed. Please try again.";
|
|
toast.error(errorMessage);
|
|
return { success: false, error: errorMessage };
|
|
}
|
|
};
|
|
|
|
const logout = () => {
|
|
localStorage.removeItem("token");
|
|
delete axios.defaults.headers.common["x-auth-token"];
|
|
setAuth({
|
|
token: null,
|
|
isAuthenticated: false,
|
|
user: null,
|
|
loading: false,
|
|
});
|
|
toast.info("You have been logged out");
|
|
};
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ auth, login, register, logout }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
};
|
|
|
|
export default AuthProvider;
|