fix: broken functionality - auth errors, toast logic, role update, routing, step library

- Extract backend error detail in auth store login/register
- Fix inverted 4xx toast logic and add 429 rate limit handling
- Send account_role field to match backend schema in role update
- Use type-aware routing for Repeat Last Session button
- Add step library placeholder page and route, remove dot badge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-19 14:22:58 -05:00
parent 47051b3ed8
commit 78b4242a76
7 changed files with 50 additions and 12 deletions

View File

@@ -25,7 +25,7 @@ export const accountsApi = {
async updateMemberRole(userId: string, role: string): Promise<AccountMember> {
const response = await apiClient.patch<AccountMember>(
`/accounts/me/members/${userId}/role`,
{ role }
{ account_role: role }
)
return response.data
},

View File

@@ -32,13 +32,15 @@ function handleGlobalError(error: AxiosError) {
return
}
// Client errors (4xx)
// Rate limit
if (status === 429) {
toast.error(data?.detail || 'Too many requests — please try again shortly')
return
}
// Client errors (4xx) — show backend detail if present
if (status >= 400 && status < 500) {
const message = data?.detail || 'Invalid request'
// Only show generic messages - pages handle specific errors
if (!data?.detail) {
toast.error(message)
}
toast.error(data?.detail || 'Invalid request')
return
}

View File

@@ -172,7 +172,7 @@ export function Sidebar() {
<NavItem href="/my-trees" icon={PenLine} label="Flow Editor" />
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={activeSessionCount || undefined} />
<NavItem href="/shares" icon={FileText} label="Exports" />
<NavItem href="/step-library" icon={Bookmark} label="Step Library" badge="dot" />
<NavItem href="/step-library" icon={Bookmark} label="Step Library" />
<NavItem href="/analytics" icon={BarChart3} label="Analytics" />
</div>

View File

@@ -0,0 +1,25 @@
import { Bookmark } from 'lucide-react'
export default function StepLibraryPage() {
return (
<div className="container mx-auto px-4 py-6 sm:px-6 sm:py-8">
<div className="mb-8">
<div className="flex items-center gap-3">
<span title="Step Library"><Bookmark className="h-8 w-8 text-muted-foreground" /></span>
<h1 className="text-2xl font-bold font-heading text-foreground sm:text-3xl">Step Library</h1>
</div>
<p className="mt-2 text-muted-foreground">Reusable steps for your flows coming soon.</p>
</div>
<div className="flex flex-col items-center justify-center py-16 text-center">
<div className="rounded-full bg-primary/10 p-4 mb-4">
<Bookmark className="h-8 w-8 text-primary" />
</div>
<h2 className="text-lg font-semibold text-foreground mb-2">Coming Soon</h2>
<p className="max-w-md text-sm text-muted-foreground">
The Step Library will let you create, share, and reuse common troubleshooting steps across all your flows.
</p>
</div>
</div>
)
}

View File

@@ -75,7 +75,7 @@ export function TreeLibraryPage() {
const lastSessionData = (() => {
const raw = safeGetItem('last-session')
if (!raw) return null
try { return JSON.parse(raw) as { tree_id: string; tree_name: string; client_name: string; ticket_number: string } }
try { return JSON.parse(raw) as { tree_id: string; tree_name: string; client_name: string; ticket_number: string; tree_type?: string } }
catch { return null }
})()
@@ -450,7 +450,7 @@ export function TreeLibraryPage() {
{lastSessionData && (
<div className="mb-6">
<button
onClick={() => navigate(`/trees/${lastSessionData.tree_id}/navigate`, {
onClick={() => navigate(getSessionResumePath(lastSessionData.tree_id, lastSessionData.tree_type), {
state: { prefillClientName: lastSessionData.client_name, prefillTicketNumber: lastSessionData.ticket_number },
})}
className={cn(

View File

@@ -31,6 +31,7 @@ const MySharesPage = lazy(() => import('@/pages/MySharesPage'))
const TeamAnalyticsPage = lazy(() => import('@/pages/TeamAnalyticsPage'))
const MyAnalyticsPage = lazy(() => import('@/pages/MyAnalyticsPage'))
const FeedbackPage = lazy(() => import('@/pages/FeedbackPage'))
const StepLibraryPage = lazy(() => import('@/pages/StepLibraryPage'))
const AccountSettingsPage = lazy(() => import('@/pages/AccountSettingsPage'))
// Admin pages
const AdminLayout = lazy(() => import('@/components/admin/AdminLayout'))
@@ -235,6 +236,14 @@ export const router = createBrowserRouter([
</Suspense>
),
},
{
path: 'step-library',
element: (
<Suspense fallback={<PageLoader />}>
<StepLibraryPage />
</Suspense>
),
},
// Admin routes
{
path: 'admin',

View File

@@ -48,7 +48,8 @@ export const useAuthStore = create<AuthState>()(
// Fetch user info
await get().fetchUser()
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Login failed'
const axiosErr = error as { response?: { data?: { detail?: string } } }
const message = axiosErr.response?.data?.detail || (error instanceof Error ? error.message : 'Login failed')
set({ error: message, isLoading: false })
throw error
}
@@ -61,7 +62,8 @@ export const useAuthStore = create<AuthState>()(
// After registration, log the user in
await get().login({ email: data.email, password: data.password })
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Registration failed'
const axiosErr = error as { response?: { data?: { detail?: string } } }
const message = axiosErr.response?.data?.detail || (error instanceof Error ? error.message : 'Registration failed')
set({ error: message, isLoading: false })
throw error
}