mirror of https://github.com/kortix-ai/suna.git
chore(dev): react-query setup, ui redesign - iteration 1
This commit is contained in:
parent
d2bbd1bd27
commit
9c1919f579
|
@ -4,15 +4,15 @@ import { useEffect, useState } from 'react';
|
||||||
import { SidebarLeft } from '@/components/sidebar/sidebar-left';
|
import { SidebarLeft } from '@/components/sidebar/sidebar-left';
|
||||||
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
|
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
|
||||||
// import { PricingAlert } from "@/components/billing/pricing-alert"
|
// import { PricingAlert } from "@/components/billing/pricing-alert"
|
||||||
import { MaintenanceAlert } from "@/components/maintenance-alert"
|
import { MaintenanceAlert } from '@/components/maintenance-alert';
|
||||||
import { useAccounts } from "@/hooks/use-accounts"
|
import { useAccounts } from '@/hooks/use-accounts';
|
||||||
import { useAuth } from "@/components/AuthProvider"
|
import { useAuth } from '@/components/AuthProvider';
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from 'next/navigation';
|
||||||
import { Loader2 } from "lucide-react"
|
import { Loader2 } from 'lucide-react';
|
||||||
import { checkApiHealth } from "@/lib/api"
|
import { checkApiHealth } from '@/lib/api';
|
||||||
import { MaintenancePage } from "@/components/maintenance/maintenance-page"
|
import { MaintenancePage } from '@/components/maintenance/maintenance-page';
|
||||||
import { DeleteOperationProvider } from "@/contexts/DeleteOperationContext"
|
import { DeleteOperationProvider } from '@/contexts/DeleteOperationContext';
|
||||||
import { StatusOverlay } from "@/components/ui/status-overlay"
|
import { StatusOverlay } from '@/components/ui/status-overlay';
|
||||||
|
|
||||||
interface DashboardLayoutProps {
|
interface DashboardLayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
@ -84,9 +84,7 @@ export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||||
<SidebarProvider>
|
<SidebarProvider>
|
||||||
<SidebarLeft />
|
<SidebarLeft />
|
||||||
<SidebarInset>
|
<SidebarInset>
|
||||||
<div className="bg-background">
|
<div className="bg-background">{children}</div>
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</SidebarInset>
|
</SidebarInset>
|
||||||
|
|
||||||
{/* <PricingAlert
|
{/* <PricingAlert
|
||||||
|
@ -106,5 +104,5 @@ export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||||
<StatusOverlay />
|
<StatusOverlay />
|
||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
</DeleteOperationProvider>
|
</DeleteOperationProvider>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -666,15 +666,15 @@ export function PricingSection({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// if (isLocalMode()) {
|
if (isLocalMode()) {
|
||||||
// return (
|
return (
|
||||||
// <div className="p-4 bg-muted/30 border border-border rounded-lg text-center">
|
<div className="p-4 bg-muted/30 border border-border rounded-lg text-center">
|
||||||
// <p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
// Running in local development mode - billing features are disabled
|
Running in local development mode - billing features are disabled
|
||||||
// </p>
|
</p>
|
||||||
// </div>
|
</div>
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState, useRef } from "react"
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
ArrowUpRight,
|
ArrowUpRight,
|
||||||
Link as LinkIcon,
|
Link as LinkIcon,
|
||||||
|
@ -32,12 +32,12 @@ import {
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip"
|
} from '@/components/ui/tooltip';
|
||||||
import { getProjects, getThreads, Project, deleteThread } from "@/lib/api"
|
import { getProjects, getThreads, Project, deleteThread } from '@/lib/api';
|
||||||
import Link from "next/link"
|
import Link from 'next/link';
|
||||||
import { DeleteConfirmationDialog } from "@/components/thread/DeleteConfirmationDialog"
|
import { DeleteConfirmationDialog } from '@/components/thread/DeleteConfirmationDialog';
|
||||||
import { useDeleteOperation } from '@/contexts/DeleteOperationContext'
|
import { useDeleteOperation } from '@/contexts/DeleteOperationContext';
|
||||||
|
|
||||||
// Thread with associated project info for display in sidebar
|
// Thread with associated project info for display in sidebar
|
||||||
type ThreadWithProject = {
|
type ThreadWithProject = {
|
||||||
|
@ -49,16 +49,19 @@ type ThreadWithProject = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function NavAgents() {
|
export function NavAgents() {
|
||||||
const { isMobile, state } = useSidebar()
|
const { isMobile, state } = useSidebar();
|
||||||
const [threads, setThreads] = useState<ThreadWithProject[]>([])
|
const [threads, setThreads] = useState<ThreadWithProject[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [loadingThreadId, setLoadingThreadId] = useState<string | null>(null)
|
const [loadingThreadId, setLoadingThreadId] = useState<string | null>(null);
|
||||||
const pathname = usePathname()
|
const pathname = usePathname();
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false)
|
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
||||||
const [threadToDelete, setThreadToDelete] = useState<{ id: string; name: string } | null>(null)
|
const [threadToDelete, setThreadToDelete] = useState<{
|
||||||
const [isDeleting, setIsDeleting] = useState(false)
|
id: string;
|
||||||
const isNavigatingRef = useRef(false)
|
name: string;
|
||||||
|
} | null>(null);
|
||||||
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
const isNavigatingRef = useRef(false);
|
||||||
const { performDelete, isOperationInProgress } = useDeleteOperation();
|
const { performDelete, isOperationInProgress } = useDeleteOperation();
|
||||||
const isPerformingActionRef = useRef(false);
|
const isPerformingActionRef = useRef(false);
|
||||||
|
|
||||||
|
@ -209,32 +212,36 @@ export function NavAgents() {
|
||||||
// Add event handler for completed navigation
|
// Add event handler for completed navigation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleNavigationComplete = () => {
|
const handleNavigationComplete = () => {
|
||||||
console.log("NAVIGATION - Navigation event completed");
|
console.log('NAVIGATION - Navigation event completed');
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
isNavigatingRef.current = false;
|
isNavigatingRef.current = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("popstate", handleNavigationComplete);
|
window.addEventListener('popstate', handleNavigationComplete);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("popstate", handleNavigationComplete);
|
window.removeEventListener('popstate', handleNavigationComplete);
|
||||||
// Ensure we clean up any leftover styles
|
// Ensure we clean up any leftover styles
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Reset isNavigatingRef when pathname changes
|
// Reset isNavigatingRef when pathname changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
isNavigatingRef.current = false;
|
isNavigatingRef.current = false;
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
// Function to handle thread click with loading state
|
// Function to handle thread click with loading state
|
||||||
const handleThreadClick = (e: React.MouseEvent<HTMLAnchorElement>, threadId: string, url: string) => {
|
const handleThreadClick = (
|
||||||
e.preventDefault()
|
e: React.MouseEvent<HTMLAnchorElement>,
|
||||||
setLoadingThreadId(threadId)
|
threadId: string,
|
||||||
router.push(url)
|
url: string,
|
||||||
}
|
) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setLoadingThreadId(threadId);
|
||||||
|
router.push(url);
|
||||||
|
};
|
||||||
|
|
||||||
// Function to handle thread deletion
|
// Function to handle thread deletion
|
||||||
const handleDeleteThread = async (threadId: string, threadName: string) => {
|
const handleDeleteThread = async (threadId: string, threadName: string) => {
|
||||||
|
@ -258,9 +265,9 @@ export function NavAgents() {
|
||||||
const deletedThread = { ...threadToDelete };
|
const deletedThread = { ...threadToDelete };
|
||||||
|
|
||||||
// Log operation start
|
// Log operation start
|
||||||
console.log("DELETION - Starting thread deletion process", {
|
console.log('DELETION - Starting thread deletion process', {
|
||||||
threadId: deletedThread.id,
|
threadId: deletedThread.id,
|
||||||
isCurrentThread: isActive
|
isCurrentThread: isActive,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use the centralized deletion system with completion callback
|
// Use the centralized deletion system with completion callback
|
||||||
|
@ -272,17 +279,17 @@ export function NavAgents() {
|
||||||
await deleteThread(threadId);
|
await deleteThread(threadId);
|
||||||
|
|
||||||
// Update the thread list
|
// Update the thread list
|
||||||
setThreads(prev => prev.filter(t => t.threadId !== threadId));
|
setThreads((prev) => prev.filter((t) => t.threadId !== threadId));
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
toast.success("Conversation deleted successfully");
|
toast.success('Conversation deleted successfully');
|
||||||
},
|
},
|
||||||
// Completion callback to reset local state
|
// Completion callback to reset local state
|
||||||
() => {
|
() => {
|
||||||
setThreadToDelete(null);
|
setThreadToDelete(null);
|
||||||
setIsDeleting(false);
|
setIsDeleting(false);
|
||||||
isPerformingActionRef.current = false;
|
isPerformingActionRef.current = false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -428,7 +435,14 @@ export function NavAgents() {
|
||||||
</a>
|
</a>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onClick={() => handleDeleteThread(thread.threadId, thread.projectName)}>
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleDeleteThread(
|
||||||
|
thread.threadId,
|
||||||
|
thread.projectName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
<Trash2 className="text-muted-foreground" />
|
<Trash2 className="text-muted-foreground" />
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import React from "react"
|
import React from 'react';
|
||||||
import { Loader2 } from "lucide-react"
|
import { Loader2 } from 'lucide-react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
|
@ -12,14 +12,14 @@ import {
|
||||||
AlertDialogFooter,
|
AlertDialogFooter,
|
||||||
AlertDialogHeader,
|
AlertDialogHeader,
|
||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
} from "@/components/ui/alert-dialog"
|
} from '@/components/ui/alert-dialog';
|
||||||
|
|
||||||
interface DeleteConfirmationDialogProps {
|
interface DeleteConfirmationDialogProps {
|
||||||
isOpen: boolean
|
isOpen: boolean;
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
onConfirm: () => void
|
onConfirm: () => void;
|
||||||
threadName: string
|
threadName: string;
|
||||||
isDeleting: boolean
|
isDeleting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +38,7 @@ export function DeleteConfirmationDialog({
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>Delete conversation</AlertDialogTitle>
|
<AlertDialogTitle>Delete conversation</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
Are you sure you want to delete the conversation{" "}
|
Are you sure you want to delete the conversation{' '}
|
||||||
<span className="font-semibold">"{threadName}"</span>?
|
<span className="font-semibold">"{threadName}"</span>?
|
||||||
<br />
|
<br />
|
||||||
This action cannot be undone.
|
This action cannot be undone.
|
||||||
|
@ -48,8 +48,8 @@ export function DeleteConfirmationDialog({
|
||||||
<AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
|
<AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
onConfirm()
|
onConfirm();
|
||||||
}}
|
}}
|
||||||
disabled={isDeleting}
|
disabled={isDeleting}
|
||||||
className="bg-destructive text-white hover:bg-destructive/90"
|
className="bg-destructive text-white hover:bg-destructive/90"
|
||||||
|
@ -60,11 +60,11 @@ export function DeleteConfirmationDialog({
|
||||||
Deleting...
|
Deleting...
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
"Delete"
|
'Delete'
|
||||||
)}
|
)}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
)
|
);
|
||||||
}
|
}
|
|
@ -46,7 +46,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
|
||||||
case 'base-only':
|
case 'base-only':
|
||||||
return {
|
return {
|
||||||
icon: <Crown className="h-3 w-3 text-blue-500" />,
|
icon: <Crown className="h-3 w-3 text-blue-500" />,
|
||||||
tooltip: 'Requires Base plan or higher',
|
tooltip: 'Requires Pro plan or higher',
|
||||||
};
|
};
|
||||||
case 'extra-only':
|
case 'extra-only':
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import React, { createContext, useContext, useReducer, useEffect, useRef } from 'react';
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useReducer,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
type DeleteState = {
|
type DeleteState = {
|
||||||
isDeleting: boolean;
|
isDeleting: boolean;
|
||||||
|
@ -17,7 +23,7 @@ const initialState: DeleteState = {
|
||||||
isDeleting: false,
|
isDeleting: false,
|
||||||
targetId: null,
|
targetId: null,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
operation: 'none'
|
operation: 'none',
|
||||||
};
|
};
|
||||||
|
|
||||||
function deleteReducer(state: DeleteState, action: DeleteAction): DeleteState {
|
function deleteReducer(state: DeleteState, action: DeleteAction): DeleteState {
|
||||||
|
@ -28,18 +34,18 @@ function deleteReducer(state: DeleteState, action: DeleteAction): DeleteState {
|
||||||
isDeleting: true,
|
isDeleting: true,
|
||||||
targetId: action.id,
|
targetId: action.id,
|
||||||
isActive: action.isActive,
|
isActive: action.isActive,
|
||||||
operation: 'pending'
|
operation: 'pending',
|
||||||
};
|
};
|
||||||
case 'DELETE_SUCCESS':
|
case 'DELETE_SUCCESS':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
operation: 'success'
|
operation: 'success',
|
||||||
};
|
};
|
||||||
case 'DELETE_ERROR':
|
case 'DELETE_ERROR':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isDeleting: false,
|
isDeleting: false,
|
||||||
operation: 'error'
|
operation: 'error',
|
||||||
};
|
};
|
||||||
case 'RESET':
|
case 'RESET':
|
||||||
return initialState;
|
return initialState;
|
||||||
|
@ -55,14 +61,20 @@ type DeleteOperationContextType = {
|
||||||
id: string,
|
id: string,
|
||||||
isActive: boolean,
|
isActive: boolean,
|
||||||
deleteFunction: () => Promise<void>,
|
deleteFunction: () => Promise<void>,
|
||||||
onComplete?: () => void
|
onComplete?: () => void,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
isOperationInProgress: React.MutableRefObject<boolean>;
|
isOperationInProgress: React.MutableRefObject<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DeleteOperationContext = createContext<DeleteOperationContextType | undefined>(undefined);
|
const DeleteOperationContext = createContext<
|
||||||
|
DeleteOperationContextType | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
export function DeleteOperationProvider({ children }: { children: React.ReactNode }) {
|
export function DeleteOperationProvider({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
const [state, dispatch] = useReducer(deleteReducer, initialState);
|
const [state, dispatch] = useReducer(deleteReducer, initialState);
|
||||||
const isOperationInProgress = useRef(false);
|
const isOperationInProgress = useRef(false);
|
||||||
|
|
||||||
|
@ -75,7 +87,7 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
// Use window.location for reliable navigation
|
// Use window.location for reliable navigation
|
||||||
window.location.pathname = '/dashboard';
|
window.location.pathname = '/dashboard';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Navigation error:", error);
|
console.error('Navigation error:', error);
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
|
@ -88,13 +100,13 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
dispatch({ type: 'RESET' });
|
dispatch({ type: 'RESET' });
|
||||||
// Ensure pointer events are restored
|
// Ensure pointer events are restored
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
isOperationInProgress.current = false;
|
isOperationInProgress.current = false;
|
||||||
|
|
||||||
// Restore sidebar menu interactivity
|
// Restore sidebar menu interactivity
|
||||||
const sidebarMenu = document.querySelector(".sidebar-menu");
|
const sidebarMenu = document.querySelector('.sidebar-menu');
|
||||||
if (sidebarMenu) {
|
if (sidebarMenu) {
|
||||||
sidebarMenu.classList.remove("pointer-events-none");
|
sidebarMenu.classList.remove('pointer-events-none');
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
|
@ -102,13 +114,13 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
|
|
||||||
if (state.operation === 'error') {
|
if (state.operation === 'error') {
|
||||||
// Reset on error immediately
|
// Reset on error immediately
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
isOperationInProgress.current = false;
|
isOperationInProgress.current = false;
|
||||||
|
|
||||||
// Restore sidebar menu interactivity
|
// Restore sidebar menu interactivity
|
||||||
const sidebarMenu = document.querySelector(".sidebar-menu");
|
const sidebarMenu = document.querySelector('.sidebar-menu');
|
||||||
if (sidebarMenu) {
|
if (sidebarMenu) {
|
||||||
sidebarMenu.classList.remove("pointer-events-none");
|
sidebarMenu.classList.remove('pointer-events-none');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [state.operation, state.isActive]);
|
}, [state.operation, state.isActive]);
|
||||||
|
@ -117,19 +129,19 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
id: string,
|
id: string,
|
||||||
isActive: boolean,
|
isActive: boolean,
|
||||||
deleteFunction: () => Promise<void>,
|
deleteFunction: () => Promise<void>,
|
||||||
onComplete?: () => void
|
onComplete?: () => void,
|
||||||
) => {
|
) => {
|
||||||
// Prevent multiple operations
|
// Prevent multiple operations
|
||||||
if (isOperationInProgress.current) return;
|
if (isOperationInProgress.current) return;
|
||||||
isOperationInProgress.current = true;
|
isOperationInProgress.current = true;
|
||||||
|
|
||||||
// Disable pointer events during operation
|
// Disable pointer events during operation
|
||||||
document.body.style.pointerEvents = "none";
|
document.body.style.pointerEvents = 'none';
|
||||||
|
|
||||||
// Disable sidebar menu interactions
|
// Disable sidebar menu interactions
|
||||||
const sidebarMenu = document.querySelector(".sidebar-menu");
|
const sidebarMenu = document.querySelector('.sidebar-menu');
|
||||||
if (sidebarMenu) {
|
if (sidebarMenu) {
|
||||||
sidebarMenu.classList.add("pointer-events-none");
|
sidebarMenu.classList.add('pointer-events-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({ type: 'START_DELETE', id, isActive });
|
dispatch({ type: 'START_DELETE', id, isActive });
|
||||||
|
@ -145,10 +157,10 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
// For non-active threads, restore interaction with delay
|
// For non-active threads, restore interaction with delay
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
|
|
||||||
if (sidebarMenu) {
|
if (sidebarMenu) {
|
||||||
sidebarMenu.classList.remove("pointer-events-none");
|
sidebarMenu.classList.remove('pointer-events-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the completion callback
|
// Call the completion callback
|
||||||
|
@ -157,14 +169,14 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Delete operation failed:", error);
|
console.error('Delete operation failed:', error);
|
||||||
|
|
||||||
// Reset states on error
|
// Reset states on error
|
||||||
document.body.style.pointerEvents = "auto";
|
document.body.style.pointerEvents = 'auto';
|
||||||
isOperationInProgress.current = false;
|
isOperationInProgress.current = false;
|
||||||
|
|
||||||
if (sidebarMenu) {
|
if (sidebarMenu) {
|
||||||
sidebarMenu.classList.remove("pointer-events-none");
|
sidebarMenu.classList.remove('pointer-events-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({ type: 'DELETE_ERROR' });
|
dispatch({ type: 'DELETE_ERROR' });
|
||||||
|
@ -175,12 +187,14 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DeleteOperationContext.Provider value={{
|
<DeleteOperationContext.Provider
|
||||||
|
value={{
|
||||||
state,
|
state,
|
||||||
dispatch,
|
dispatch,
|
||||||
performDelete,
|
performDelete,
|
||||||
isOperationInProgress
|
isOperationInProgress,
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</DeleteOperationContext.Provider>
|
</DeleteOperationContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -189,7 +203,9 @@ export function DeleteOperationProvider({ children }: { children: React.ReactNod
|
||||||
export function useDeleteOperation() {
|
export function useDeleteOperation() {
|
||||||
const context = useContext(DeleteOperationContext);
|
const context = useContext(DeleteOperationContext);
|
||||||
if (context === undefined) {
|
if (context === undefined) {
|
||||||
throw new Error('useDeleteOperation must be used within a DeleteOperationProvider');
|
throw new Error(
|
||||||
|
'useDeleteOperation must be used within a DeleteOperationProvider',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
|
@ -1284,7 +1284,9 @@ export const deleteThread = async (threadId: string): Promise<void> => {
|
||||||
throw new Error(`Error deleting thread: ${threadError.message}`);
|
throw new Error(`Error deleting thread: ${threadError.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Thread ${threadId} successfully deleted with all related items`);
|
console.log(
|
||||||
|
`Thread ${threadId} successfully deleted with all related items`,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting thread and related items:', error);
|
console.error('Error deleting thread and related items:', error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
Loading…
Reference in New Issue