Add complete project detail page with real-time updates via SignalR. Changes: - Updated project detail page with edit and archive buttons - Created EditProjectDialog component for updating projects - Created ArchiveProjectDialog component for archiving projects - Integrated SignalR real-time updates (onProjectUpdated, onProjectArchived) - Added SignalR connection status indicator - Enhanced useProjectHub hook to support callback options - Improved UI layout with two-column card grid - Added toast notifications for user feedback Features: - View project details (name, description, status, timestamps) - Edit project name and description - Archive active projects - Real-time updates when project is modified by other users - Automatic redirect when project is archived 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import { useRouter } from 'next/navigation';
|
|
import { useDeleteProject } from '@/lib/hooks/use-projects';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import { Button } from '@/components/ui/button';
|
|
import { toast } from 'sonner';
|
|
|
|
interface ArchiveProjectDialogProps {
|
|
projectId: string;
|
|
projectName: string;
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
}
|
|
|
|
export function ArchiveProjectDialog({
|
|
projectId,
|
|
projectName,
|
|
open,
|
|
onOpenChange,
|
|
}: ArchiveProjectDialogProps) {
|
|
const router = useRouter();
|
|
const deleteProject = useDeleteProject();
|
|
|
|
const handleArchive = async () => {
|
|
try {
|
|
await deleteProject.mutateAsync(projectId);
|
|
toast.success('Project archived successfully');
|
|
router.push('/projects');
|
|
} catch (error) {
|
|
toast.error('Failed to archive project');
|
|
console.error('Archive error:', error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-[425px]">
|
|
<DialogHeader>
|
|
<DialogTitle>Archive Project</DialogTitle>
|
|
<DialogDescription>
|
|
Are you sure you want to archive{' '}
|
|
<strong className="font-semibold">{projectName}</strong>?
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="py-4">
|
|
<p className="text-sm text-muted-foreground">
|
|
This action will mark the project as archived, but it can be
|
|
restored later. All associated issues and data will be preserved.
|
|
</p>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={() => onOpenChange(false)}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
variant="destructive"
|
|
onClick={handleArchive}
|
|
disabled={deleteProject.isPending}
|
|
>
|
|
{deleteProject.isPending ? 'Archiving...' : 'Archive Project'}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|