mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
fix: prevent unnecessary refetches in webapp dashboard and review pages
Use primitive currentOrgId instead of currentOrg object in React dependency arrays to avoid refetches on reference changes. Guard dashboard fetch behind loadingViewMode. Prevent same-route sidebar navigation from triggering page reloads. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ea23cf06a6
commit
f9aeeca573
3 changed files with 30 additions and 20 deletions
|
|
@ -227,6 +227,7 @@ export default function StagingPage() {
|
|||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
const { currentOrg, loading: isLoadingViewMode } = useViewMode()
|
||||
const currentOrgId = currentOrg?.id ?? null
|
||||
|
||||
const [availableRepositories, setAvailableRepositories] = useState<
|
||||
Array<{ id: string; full_name: string }>
|
||||
|
|
@ -271,8 +272,6 @@ export default function StagingPage() {
|
|||
|
||||
// Reset repository filter immediately when switching contexts (synchronously, before other effects)
|
||||
useLayoutEffect(() => {
|
||||
const currentOrgId = currentOrg?.id ?? null
|
||||
|
||||
// Skip on initial mount
|
||||
if (previousOrgId.current === undefined) {
|
||||
previousOrgId.current = currentOrgId
|
||||
|
|
@ -294,7 +293,7 @@ export default function StagingPage() {
|
|||
|
||||
previousOrgId.current = currentOrgId
|
||||
}
|
||||
}, [currentOrg])
|
||||
}, [currentOrgId])
|
||||
|
||||
// Load repositories with staging events
|
||||
useEffect(() => {
|
||||
|
|
@ -303,8 +302,8 @@ export default function StagingPage() {
|
|||
try {
|
||||
const userSession = await getUserIdAndUsername()
|
||||
const repos = await getRepositoriesWithStagingEvents(
|
||||
currentOrg
|
||||
? { orgId: currentOrg.id }
|
||||
currentOrgId
|
||||
? { orgId: currentOrgId }
|
||||
: { userId: userSession.userId, username: userSession.username },
|
||||
)
|
||||
setAvailableRepositories(repos)
|
||||
|
|
@ -316,7 +315,7 @@ export default function StagingPage() {
|
|||
if (!isLoadingUser && !isLoadingViewMode && userId) {
|
||||
loadRepositories()
|
||||
}
|
||||
}, [userId, isLoadingUser, isLoadingViewMode, currentOrg])
|
||||
}, [userId, isLoadingUser, isLoadingViewMode, currentOrgId])
|
||||
|
||||
// Memoized load events function
|
||||
const loadEvents = useCallback(async () => {
|
||||
|
|
@ -364,8 +363,8 @@ export default function StagingPage() {
|
|||
|
||||
const userSession = await getUserIdAndUsername()
|
||||
const data = await getAllOptimizationEvents({
|
||||
payload: currentOrg
|
||||
? { orgId: currentOrg.id }
|
||||
payload: currentOrgId
|
||||
? { orgId: currentOrgId }
|
||||
: { userId: userSession.userId, username: userSession.username },
|
||||
search: filters.search,
|
||||
filter,
|
||||
|
|
@ -398,7 +397,7 @@ export default function StagingPage() {
|
|||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [userId, filters, currentOrg, pageSize])
|
||||
}, [userId, filters, currentOrgId, pageSize])
|
||||
|
||||
// Load events when filters change - with debounce for search
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ interface ActiveUserData {
|
|||
}
|
||||
|
||||
function Dashboard() {
|
||||
const { currentOrg } = useViewMode()
|
||||
const { currentOrg, loading: loadingViewMode } = useViewMode()
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
const [repositories, setRepositories] = useState<RepositoryWithUsage[]>([])
|
||||
|
|
@ -207,8 +207,10 @@ function Dashboard() {
|
|||
}, [selectedYear, currentOrgId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingViewMode) {
|
||||
fetchDashboardData()
|
||||
}, [fetchDashboardData])
|
||||
}
|
||||
}, [fetchDashboardData, loadingViewMode])
|
||||
|
||||
const handleYearChange = useCallback((year: number) => {
|
||||
setSelectedYear(year)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"
|
|||
import LogoBox from "@/components/dashboard/logo-box"
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
import React, { useEffect, useState, useRef, type JSX } from "react"
|
||||
import React, { useEffect, useState, useRef, useCallback, type JSX, type MouseEvent } from "react"
|
||||
import Image from "next/image"
|
||||
import {
|
||||
FolderGit2,
|
||||
|
|
@ -74,6 +74,15 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
|
||||
const isMemberOfOrg = mode === "organization" && !!currentOrg
|
||||
|
||||
const preventSameRouteNavigation = useCallback(
|
||||
(href: string) => (e: MouseEvent) => {
|
||||
if (currentRoute === href) {
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
[currentRoute],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const savedTheme = localStorage.getItem("theme")
|
||||
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
|
|
@ -243,7 +252,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="px-3 py-4">
|
||||
{/* Main Navigation Group - Always visible */}
|
||||
<Link href="/dashboard" className="block mb-1">
|
||||
<Link href="/dashboard" className="block mb-1" onClick={preventSameRouteNavigation("/dashboard")}>
|
||||
<Button
|
||||
variant={currentRoute === "/dashboard" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -253,7 +262,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="/review-optimizations" className="block mb-1">
|
||||
<Link href="/review-optimizations" className="block mb-1" onClick={preventSameRouteNavigation("/review-optimizations")}>
|
||||
<Button
|
||||
variant={currentRoute === "/review-optimizations" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -264,7 +273,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
</Link>
|
||||
|
||||
{/* Show full navigation for personal mode or admin/owner in org mode */}
|
||||
<Link href="/repositories" className="block mb-1">
|
||||
<Link href="/repositories" className="block mb-1" onClick={preventSameRouteNavigation("/repositories")}>
|
||||
<Button
|
||||
variant={currentRoute === "/repositories" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -276,7 +285,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
|
||||
{/* Members tab - only for org members */}
|
||||
{isMemberOfOrg && (
|
||||
<Link href="/members" className="block mb-1">
|
||||
<Link href="/members" className="block mb-1" onClick={preventSameRouteNavigation("/members")}>
|
||||
<Button
|
||||
variant={currentRoute === "/members" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -323,7 +332,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
</div>
|
||||
|
||||
{/* Configuration Group */}
|
||||
<Link href="/getting-started" className="block mb-1">
|
||||
<Link href="/getting-started" className="block mb-1" onClick={preventSameRouteNavigation("/getting-started")}>
|
||||
<Button
|
||||
variant={currentRoute === "/getting-started" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -345,7 +354,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
<div className="h-px bg-border" />
|
||||
</div>
|
||||
|
||||
<Link href="/apikeys" className="block mb-1">
|
||||
<Link href="/apikeys" className="block mb-1" onClick={preventSameRouteNavigation("/apikeys")}>
|
||||
<Button
|
||||
variant={currentRoute === "/apikeys" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
@ -357,7 +366,7 @@ export function Sidebar({ className, user, isLoading, error }: SidebarProps): JS
|
|||
|
||||
{/* Billing - Only for Personal Account */}
|
||||
{mode === "personal" && (
|
||||
<Link href="/billing" className="block mb-1">
|
||||
<Link href="/billing" className="block mb-1" onClick={preventSameRouteNavigation("/billing")}>
|
||||
<Button
|
||||
variant={currentRoute === "/billing" ? "secondary" : "ghost"}
|
||||
className="flex items-center justify-start w-full"
|
||||
|
|
|
|||
Loading…
Reference in a new issue