refactor: enhance sidebar functionality with new hooks and components

- Introduced new hooks: useRunningAgents, useTrashOperations, useProjectPicker, useSpecRegeneration, and useNavigation for improved state management and functionality.
- Created CollapseToggleButton component for sidebar collapse functionality, enhancing UI responsiveness.
- Refactored sidebar.tsx to utilize the new hooks and components, improving code organization and maintainability.
- Updated sidebar structure to streamline project selection and navigation processes.

This refactor aims to enhance user experience and maintainability by modularizing functionality and improving the sidebar's responsiveness.
This commit is contained in:
Kacper
2025-12-21 20:20:50 +01:00
parent 7fac115a36
commit b641884c37
9 changed files with 679 additions and 431 deletions

View File

@@ -0,0 +1,92 @@
import { useState, useCallback } from 'react';
import { toast } from 'sonner';
import { getElectronAPI, type TrashedProject } from '@/lib/electron';
interface UseTrashOperationsProps {
restoreTrashedProject: (projectId: string) => void;
deleteTrashedProject: (projectId: string) => void;
emptyTrash: () => void;
trashedProjects: TrashedProject[];
}
export function useTrashOperations({
restoreTrashedProject,
deleteTrashedProject,
emptyTrash,
trashedProjects,
}: UseTrashOperationsProps) {
const [activeTrashId, setActiveTrashId] = useState<string | null>(null);
const [isEmptyingTrash, setIsEmptyingTrash] = useState(false);
const handleRestoreProject = useCallback(
(projectId: string) => {
restoreTrashedProject(projectId);
toast.success('Project restored', {
description: 'Added back to your project list.',
});
},
[restoreTrashedProject]
);
const handleDeleteProjectFromDisk = useCallback(
async (trashedProject: TrashedProject) => {
const confirmed = window.confirm(
`Delete "${trashedProject.name}" from disk?\nThis sends the folder to your system Trash.`
);
if (!confirmed) return;
setActiveTrashId(trashedProject.id);
try {
const api = getElectronAPI();
if (!api.trashItem) {
throw new Error('System Trash is not available in this build.');
}
const result = await api.trashItem(trashedProject.path);
if (!result.success) {
throw new Error(result.error || 'Failed to delete project folder');
}
deleteTrashedProject(trashedProject.id);
toast.success('Project folder sent to system Trash', {
description: trashedProject.path,
});
} catch (error) {
console.error('[Sidebar] Failed to delete project from disk:', error);
toast.error('Failed to delete project folder', {
description: error instanceof Error ? error.message : 'Unknown error',
});
} finally {
setActiveTrashId(null);
}
},
[deleteTrashedProject]
);
const handleEmptyTrash = useCallback(() => {
if (trashedProjects.length === 0) {
return;
}
const confirmed = window.confirm(
'Clear all projects from recycle bin? This does not delete folders from disk.'
);
if (!confirmed) return;
setIsEmptyingTrash(true);
try {
emptyTrash();
toast.success('Recycle bin cleared');
} finally {
setIsEmptyingTrash(false);
}
}, [emptyTrash, trashedProjects.length]);
return {
activeTrashId,
isEmptyingTrash,
handleRestoreProject,
handleDeleteProjectFromDisk,
handleEmptyTrash,
};
}