feat: implement navigation context and enhance component loading states across the application

This commit is contained in:
Arunavo Ray
2025-05-24 12:51:57 +05:30
parent a3ac31795c
commit 70b3e412ad
9 changed files with 229 additions and 48 deletions

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useState, useRef } from 'react';
import { useAuth } from './useAuth';
import { apiRequest } from '@/lib/utils';
import type { ConfigApiResponse } from '@/types/config';
@@ -11,9 +11,19 @@ interface ConfigStatus {
error: string | null;
}
// Cache to prevent duplicate API calls across components
let configCache: { data: ConfigApiResponse | null; timestamp: number; userId: string | null } = {
data: null,
timestamp: 0,
userId: null
};
const CACHE_DURATION = 30000; // 30 seconds cache
/**
* Hook to check if GitHub and Gitea are properly configured
* Returns configuration status and prevents unnecessary API calls when not configured
* Uses caching to prevent duplicate API calls across components
*/
export function useConfigStatus(): ConfigStatus {
const { user } = useAuth();
@@ -25,6 +35,9 @@ export function useConfigStatus(): ConfigStatus {
error: null,
});
// Track if this hook has already checked config to prevent multiple calls
const hasCheckedRef = useRef(false);
const checkConfiguration = useCallback(async () => {
if (!user?.id) {
setConfigStatus({
@@ -37,22 +50,23 @@ export function useConfigStatus(): ConfigStatus {
return;
}
try {
setConfigStatus(prev => ({ ...prev, isLoading: true, error: null }));
// Check cache first
const now = Date.now();
const isCacheValid = configCache.data &&
configCache.userId === user.id &&
(now - configCache.timestamp) < CACHE_DURATION;
const configResponse = await apiRequest<ConfigApiResponse>(
`/config?userId=${user.id}`,
{ method: 'GET' }
);
if (isCacheValid && hasCheckedRef.current) {
const configResponse = configCache.data!;
const isGitHubConfigured = !!(
configResponse?.githubConfig?.username &&
configResponse?.githubConfig?.username &&
configResponse?.githubConfig?.token
);
const isGiteaConfigured = !!(
configResponse?.giteaConfig?.url &&
configResponse?.giteaConfig?.username &&
configResponse?.giteaConfig?.url &&
configResponse?.giteaConfig?.username &&
configResponse?.giteaConfig?.token
);
@@ -65,6 +79,49 @@ export function useConfigStatus(): ConfigStatus {
isLoading: false,
error: null,
});
return;
}
try {
// Only show loading if we haven't checked before or cache is invalid
if (!hasCheckedRef.current) {
setConfigStatus(prev => ({ ...prev, isLoading: true, error: null }));
}
const configResponse = await apiRequest<ConfigApiResponse>(
`/config?userId=${user.id}`,
{ method: 'GET' }
);
// Update cache
configCache = {
data: configResponse,
timestamp: now,
userId: user.id
};
const isGitHubConfigured = !!(
configResponse?.githubConfig?.username &&
configResponse?.githubConfig?.token
);
const isGiteaConfigured = !!(
configResponse?.giteaConfig?.url &&
configResponse?.giteaConfig?.username &&
configResponse?.giteaConfig?.token
);
const isFullyConfigured = isGitHubConfigured && isGiteaConfigured;
setConfigStatus({
isGitHubConfigured,
isGiteaConfigured,
isFullyConfigured,
isLoading: false,
error: null,
});
hasCheckedRef.current = true;
} catch (error) {
setConfigStatus({
isGitHubConfigured: false,
@@ -73,6 +130,7 @@ export function useConfigStatus(): ConfigStatus {
isLoading: false,
error: error instanceof Error ? error.message : 'Failed to check configuration',
});
hasCheckedRef.current = true;
}
}, [user?.id]);
@@ -82,3 +140,8 @@ export function useConfigStatus(): ConfigStatus {
return configStatus;
}
// Export function to invalidate cache when config is updated
export function invalidateConfigCache() {
configCache = { data: null, timestamp: 0, userId: null };
}