From b477894027632fa7089d580305650db5bf980ad5 Mon Sep 17 00:00:00 2001 From: bryan Date: Thu, 15 Jan 2026 13:40:21 -0800 Subject: [PATCH] fixed error display in login and register, added log out button --- hive/src/controllers/user.controller.ts | 9 +- .../agent-control/AgentControlLayout.tsx | 136 ++++++++++-------- honeycomb/src/services/api.ts | 18 ++- honeycomb/src/stores/userStore.ts | 7 +- 4 files changed, 103 insertions(+), 67 deletions(-) diff --git a/hive/src/controllers/user.controller.ts b/hive/src/controllers/user.controller.ts index d6d39ff5..f3ba88d7 100644 --- a/hive/src/controllers/user.controller.ts +++ b/hive/src/controllers/user.controller.ts @@ -106,7 +106,14 @@ router.post( console.error("[UserController] login-v2 error:", err.message); // Handle specific error codes - if (err.code === "USER_NOT_FOUND" || err.code === "INVALID_CREDENTIALS") { + if (err.code === "USER_NOT_FOUND") { + return res.status(401).json({ + success: false, + msg: "User not found. Please sign up for an account.", + }); + } + + if (err.code === "INVALID_CREDENTIALS") { return res.status(401).json({ success: false, msg: "Invalid email or password", diff --git a/honeycomb/src/components/agent-control/AgentControlLayout.tsx b/honeycomb/src/components/agent-control/AgentControlLayout.tsx index 30c2af74..fc7c5436 100644 --- a/honeycomb/src/components/agent-control/AgentControlLayout.tsx +++ b/honeycomb/src/components/agent-control/AgentControlLayout.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react' import { Outlet, NavLink, useNavigate, useLocation } from 'react-router-dom' import { useControlSocket } from '@/hooks/useControlSocket' import { useAgentControlStore } from '@/stores/agentControlStore' -import { useUserStore } from '@/stores/userStore' +import { useUserStore, type UserState } from '@/stores/userStore' import { useSidebarCollapsed } from '@/hooks/usePersistedSettings' import { NotificationBell } from './shared/NotificationBell' import { @@ -32,6 +32,7 @@ import { PanelLeft, Settings, Sparkles, + LogOut, HelpCircle, ExternalLink, FileText, @@ -53,8 +54,10 @@ const navItems = [ export function AgentControlLayout() { const { connect, disconnect, isConnected } = useControlSocket() const hasActiveAgents = useAgentControlStore((state) => state.eventsBuffer.length > 0) - const user = useUserStore((state) => state.user) - const fullName = useUserStore((state) => state.fullName()) + const user = useUserStore((state: UserState) => state.user) + const fullName = useUserStore((state: UserState) => state.fullName()) + const signOut = useUserStore((state: UserState) => state.signOut) + const isLoggingOut = useUserStore((state: UserState) => state.isLoggingOut) const navigate = useNavigate() const location = useLocation() const { sidebarCollapsed, toggleSidebar } = useSidebarCollapsed() @@ -178,51 +181,60 @@ export function AgentControlLayout() { - {/* User Profile Section */} - - -
e.stopPropagation()} - > -
- - {!sidebarCollapsed && ( -
-

{fullName}

-

Pro

-
+ {/* User Profile Section - hidden during logout to prevent red avatar flash */} + {!isLoggingOut && ( + + +
e.stopPropagation()} + > +
+ + {!sidebarCollapsed && ( +
+

{fullName}

+

Pro

+
+ )} +
-
- - - navigate(`${location.pathname}#settings`)} - className="cursor-pointer" - > - - Settings - - console.log('Upgrade clicked')} - className="cursor-pointer" - > - - Upgrade - - - + + + navigate(`${location.pathname}#settings`)} + className="cursor-pointer" + > + + Settings + + console.log('Upgrade clicked')} + className="cursor-pointer" + > + + Upgrade + + signOut()} + className="cursor-pointer" + > + + Log out + + + + )} {/* Right side - header bar + content */} @@ -231,23 +243,25 @@ export function AgentControlLayout() {
- {/* Connection status */} -
-
+ > + + {isConnected ? 'Connected' : 'Disconnected'} +
+ )} diff --git a/honeycomb/src/services/api.ts b/honeycomb/src/services/api.ts index 5064202e..492b46b0 100644 --- a/honeycomb/src/services/api.ts +++ b/honeycomb/src/services/api.ts @@ -18,6 +18,16 @@ class ApiClient { this.baseUrl = baseUrl } + private async parseErrorMessage(response: Response): Promise { + const text = await response.text() + try { + const json = JSON.parse(text) + return json.msg || json.message || text + } catch { + return text + } + } + private getHeaders(): HeadersInit { const headers: HeadersInit = { 'Content-Type': 'application/json', @@ -34,7 +44,7 @@ class ApiClient { }) if (!response.ok) { - throw new ApiError(response.status, await response.text()) + throw new ApiError(response.status, await this.parseErrorMessage(response)) } return response.json() @@ -48,7 +58,7 @@ class ApiClient { }) if (!response.ok) { - throw new ApiError(response.status, await response.text()) + throw new ApiError(response.status, await this.parseErrorMessage(response)) } return response.json() @@ -62,7 +72,7 @@ class ApiClient { }) if (!response.ok) { - throw new ApiError(response.status, await response.text()) + throw new ApiError(response.status, await this.parseErrorMessage(response)) } return response.json() @@ -75,7 +85,7 @@ class ApiClient { }) if (!response.ok) { - throw new ApiError(response.status, await response.text()) + throw new ApiError(response.status, await this.parseErrorMessage(response)) } return response.json() diff --git a/honeycomb/src/stores/userStore.ts b/honeycomb/src/stores/userStore.ts index 76d25343..f38518cd 100644 --- a/honeycomb/src/stores/userStore.ts +++ b/honeycomb/src/stores/userStore.ts @@ -3,12 +3,13 @@ import type { User, Organization } from '@/types/user' import * as userApi from '@/services/userApi' import * as orgApi from '@/services/orgApi' -interface UserState { +export interface UserState { user: User | null roleId: number | null org: Organization | null orgLogo: string | null isLoading: boolean + isLoggingOut: boolean // Actions setUser: (user: User) => void @@ -28,6 +29,7 @@ export const useUserStore = create((set, get) => ({ org: null, orgLogo: null, isLoading: false, + isLoggingOut: false, setUser: (user) => set({ user }), @@ -85,6 +87,9 @@ export const useUserStore = create((set, get) => ({ }, signOut: (redirectUrl) => { + // Set logging out flag FIRST - prevents flash of error states + set({ isLoggingOut: true }) + // Clear storage localStorage.removeItem('token') localStorage.removeItem('context_session_id')