WIP: Save current work before CHORUS rebrand
- Agent roles integration progress - Various backend and frontend updates - Storybook cache cleanup 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||
import { apiConfig } from '../config/api';
|
||||
|
||||
interface User {
|
||||
id: string; // UUID as string
|
||||
@@ -45,7 +46,13 @@ interface AuthProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL + '/api' || '/api';
|
||||
const API_BASE_URL = apiConfig.baseURL + '/api';
|
||||
|
||||
// Debug logging
|
||||
if (apiConfig.debug) {
|
||||
console.log('Auth API_BASE_URL:', API_BASE_URL);
|
||||
console.log('apiConfig.baseURL:', apiConfig.baseURL);
|
||||
}
|
||||
|
||||
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
@@ -127,6 +134,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
|
||||
localStorage.setItem('hive_tokens', JSON.stringify(newTokens));
|
||||
localStorage.setItem('hive_user', JSON.stringify(data.user));
|
||||
localStorage.setItem('token', newTokens.access_token);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
@@ -168,6 +176,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
// Store in localStorage
|
||||
localStorage.setItem('hive_tokens', JSON.stringify(newTokens));
|
||||
localStorage.setItem('hive_user', JSON.stringify(data.user));
|
||||
localStorage.setItem('token', newTokens.access_token);
|
||||
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message || 'Login failed');
|
||||
@@ -203,6 +212,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
// Store in localStorage
|
||||
localStorage.setItem('hive_tokens', JSON.stringify(newTokens));
|
||||
localStorage.setItem('hive_user', JSON.stringify(data.user));
|
||||
localStorage.setItem('token', newTokens.access_token);
|
||||
} catch (error) {
|
||||
console.error('Registration failed:', error);
|
||||
throw error;
|
||||
@@ -248,6 +258,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
setTokens(null);
|
||||
localStorage.removeItem('hive_tokens');
|
||||
localStorage.removeItem('hive_user');
|
||||
localStorage.removeItem('token');
|
||||
};
|
||||
|
||||
const contextValue: AuthContextType = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import React, { createContext, useContext, useEffect, useState, useRef } from 'react';
|
||||
import { useSocketIO, SocketIOMessage } from '../hooks/useSocketIO';
|
||||
import { useAuth } from './AuthContext';
|
||||
|
||||
interface SocketIOContextType {
|
||||
isConnected: boolean;
|
||||
@@ -45,6 +46,8 @@ export const SocketIOProvider: React.FC<SocketIOProviderProps> = ({
|
||||
</SocketIOContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const { isAuthenticated } = useAuth();
|
||||
const [subscriptions, setSubscriptions] = useState<Map<string, Set<(data: any) => void>>>(new Map());
|
||||
|
||||
const {
|
||||
@@ -91,6 +94,21 @@ export const SocketIOProvider: React.FC<SocketIOProviderProps> = ({
|
||||
// console.error('Socket.IO error:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// Reconnect when authentication status changes (but only once)
|
||||
const hasReconnectedRef = useRef(false);
|
||||
useEffect(() => {
|
||||
if (isAuthenticated && !hasReconnectedRef.current) {
|
||||
console.log('User authenticated, reconnecting Socket.IO...');
|
||||
hasReconnectedRef.current = true;
|
||||
setTimeout(() => {
|
||||
reconnect();
|
||||
}, 1000); // Delay to prevent immediate reconnection loop
|
||||
}
|
||||
if (!isAuthenticated) {
|
||||
hasReconnectedRef.current = false;
|
||||
}
|
||||
}, [isAuthenticated, reconnect]);
|
||||
|
||||
const subscribe = (messageType: string, handler: (data: any) => void) => {
|
||||
setSubscriptions(prev => {
|
||||
|
||||
65
frontend/src/contexts/ThemeContext.tsx
Normal file
65
frontend/src/contexts/ThemeContext.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
interface ThemeContextType {
|
||||
isDarkMode: boolean;
|
||||
toggleDarkMode: () => void;
|
||||
setDarkMode: (enabled: boolean) => void;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
||||
|
||||
export const useTheme = () => {
|
||||
const context = useContext(ThemeContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useTheme must be used within a ThemeProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
interface ThemeProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
|
||||
const [isDarkMode, setIsDarkMode] = useState(() => {
|
||||
// Check localStorage for saved preference
|
||||
const saved = localStorage.getItem('darkMode');
|
||||
if (saved !== null) {
|
||||
return JSON.parse(saved);
|
||||
}
|
||||
// Default to system preference
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// Apply dark mode class to document
|
||||
if (isDarkMode) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
// Save preference to localStorage
|
||||
localStorage.setItem('darkMode', JSON.stringify(isDarkMode));
|
||||
}, [isDarkMode]);
|
||||
|
||||
const toggleDarkMode = () => {
|
||||
setIsDarkMode(!isDarkMode);
|
||||
};
|
||||
|
||||
const setDarkMode = (enabled: boolean) => {
|
||||
setIsDarkMode(enabled);
|
||||
};
|
||||
|
||||
const value = {
|
||||
isDarkMode,
|
||||
toggleDarkMode,
|
||||
setDarkMode,
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={value}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user