Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions my-app/app/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ import { NodeResources } from "@/app/admin/dashboard/node-resources"
import { DashboardQuickActions } from "@/components/dashboard/dashboard-quick-actions"
import { Button } from "@/components/ui/button"
import { RefreshCw } from "lucide-react"
import { useAuth } from "@/contexts/auth-context"

export default function AdminDashboardPage() {
const { authState } = useAuth()
// Fetch unified dashboard data
const { data: dashboardData, loading, error, refetch } = useApiState({
fetchFn: getDashboardData,
enabled: authState.authenticated === true && authState.isAdmin === true,
deps: []
})

Expand Down
8 changes: 8 additions & 0 deletions my-app/app/creator/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ import { ErrorDisplay } from "@/components/ui/error-display";
import { Copy, CopyPlusIcon, Edit } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/contexts/auth-context";

export default function CreatorDashboardPage() {
const { authState } = useAuth();
const creatorOrAdmin =
authState.authenticated === true &&
(authState.isCreator === true || authState.isAdmin === true);

const {
data: templates,
loading: templatesLoading,
error: templatesError,
} = useApiState({
fetchFn: getAllPodTemplates,
enabled: creatorOrAdmin,
});

const {
Expand All @@ -26,6 +33,7 @@ export default function CreatorDashboardPage() {
error: unpublishedError,
} = useApiState({
fetchFn: getUnpublishedTemplates,
enabled: creatorOrAdmin,
});

const publishedCount = templates?.length || 0;
Expand Down
1 change: 1 addition & 0 deletions my-app/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function Page() {
error: dashboardError,
} = useApiState({
fetchFn: getUserDashboard,
enabled: authState.authenticated === true,
});

// Extract data from the unified response
Expand Down
3 changes: 3 additions & 0 deletions my-app/app/pods/deployed/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useApiState } from "@/hooks/use-api-state"
import { deletePod, getDeployedPods } from "@/lib/api"
import { DeployedPod } from "@/lib/types"
import { SectionCards } from "@/app/pods/deployed/deployed-pods-cards"
import { useAuth } from "@/contexts/auth-context"
import {
AlertDialog,
AlertDialogAction,
Expand All @@ -23,8 +24,10 @@ import {
export default function Page() {
const [alertOpen, setAlertOpen] = useState(false)
const [selectedPod, setSelectedPod] = useState<DeployedPod | null>(null)
const { authState } = useAuth()
const { data: pods, loading, error } = useApiState({
fetchFn: getDeployedPods,
enabled: authState.authenticated === true,
})

const handleDeleteClick = (pod: DeployedPod) => {
Expand Down
5 changes: 4 additions & 1 deletion my-app/app/pods/templates/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { SectionCards } from "@/app/pods/templates/pod-templates-cards"
import { getPodTemplates } from "@/lib/api"
import { PodDeployDialog } from "@/components/pod-deploy-dialog"
import { usePodDeployment } from "@/hooks/use-pod-deployment"
import { useAuth } from "@/contexts/auth-context"

export default function Page() {
const { isDialogOpen, selectedPod, openDeployDialog, closeDeployDialog } = usePodDeployment()

const { authState } = useAuth()

const { data: pods, loading, error } = useApiState({
fetchFn: getPodTemplates,
enabled: authState.authenticated === true,
})

const pageHeader = (
Expand Down
3 changes: 3 additions & 0 deletions my-app/contexts/auth-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useEffect,
useCallback,
} from "react";
import { clearRequestCache } from "@/lib/api";

interface SessionData {
authenticated: boolean;
Expand Down Expand Up @@ -110,6 +111,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
// Clear cache to force fresh request
sessionCache = null;
sessionPromise = null;
clearRequestCache();
setAuthState((prev) => ({ ...prev, loading: true }));
await checkSession();
}, [checkSession]);
Expand All @@ -120,6 +122,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
// Clear cache and update state
sessionCache = null;
sessionPromise = null;
clearRequestCache();
setAuthState({
authenticated: false,
loading: false,
Expand Down
7 changes: 6 additions & 1 deletion my-app/hooks/use-api-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"
interface UseApiStateOptions<T> {
fetchFn: () => Promise<T>
deps?: React.DependencyList
enabled?: boolean
}

interface UseApiStateReturn<T> {
Expand All @@ -12,7 +13,7 @@ interface UseApiStateReturn<T> {
refetch: () => void
}

export function useApiState<T>({ fetchFn, deps = [] }: UseApiStateOptions<T>): UseApiStateReturn<T> {
export function useApiState<T>({ fetchFn, deps = [], enabled = true }: UseApiStateOptions<T>): UseApiStateReturn<T> {
const [data, setData] = useState<T | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
Expand All @@ -31,6 +32,10 @@ export function useApiState<T>({ fetchFn, deps = [] }: UseApiStateOptions<T>): U
}

useEffect(() => {
if (!enabled) {
setLoading(true)
return
}
fetchData()
}, deps)

Expand Down
14 changes: 13 additions & 1 deletion my-app/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const requestCache = new Map<
>();
const CACHE_DURATION = 5000; // 5 seconds for deduplication

// Clear all cached/in-flight requests
export function clearRequestCache(): void {
requestCache.clear();
}

// Helper function to handle request deduplication
async function deduplicatedFetch<T>(
key: string,
Expand All @@ -49,8 +54,15 @@ async function deduplicatedFetch<T>(
// Cache the promise
requestCache.set(key, { promise, timestamp: now });

promise.catch(() => {
const entry = requestCache.get(key);
if (entry && entry.timestamp === now) {
requestCache.delete(key);
}
});

// Clean up cache after completion
promise.finally(() => {
promise.then(() => {
setTimeout(() => {
const entry = requestCache.get(key);
if (entry && entry.timestamp === now) {
Expand Down
Loading