import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Link2, Plus, Pencil, Trash2, GripVertical, Loader2, ExternalLink as ExternalLinkIcon } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { api } from '../api/client'; import type { ExternalLink } from '../api/client'; import { Card, CardContent, CardHeader } from './Card'; import { Button } from './Button'; import { AddExternalLinkModal } from './AddExternalLinkModal'; import { ConfirmModal } from './ConfirmModal'; import { getIconByName } from './IconPicker'; export function ExternalLinksSettings() { const { t } = useTranslation(); const queryClient = useQueryClient(); const [showAddModal, setShowAddModal] = useState(false); const [editingLink, setEditingLink] = useState(null); const [deletingLink, setDeletingLink] = useState(null); const [draggedId, setDraggedId] = useState(null); // Fetch external links const { data: links, isLoading } = useQuery({ queryKey: ['external-links'], queryFn: api.getExternalLinks, }); // Delete mutation const deleteMutation = useMutation({ mutationFn: (id: number) => api.deleteExternalLink(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['external-links'] }); }, }); // Reorder mutation const reorderMutation = useMutation({ mutationFn: (ids: number[]) => api.reorderExternalLinks(ids), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['external-links'] }); }, }); const handleDragStart = (e: React.DragEvent, id: number) => { setDraggedId(id); e.dataTransfer.effectAllowed = 'move'; }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; const handleDrop = (e: React.DragEvent, targetId: number) => { e.preventDefault(); if (draggedId === null || draggedId === targetId || !links) return; const currentIds = links.map((l) => l.id); const draggedIndex = currentIds.indexOf(draggedId); const targetIndex = currentIds.indexOf(targetId); if (draggedIndex === -1 || targetIndex === -1) return; // Reorder const newIds = [...currentIds]; newIds.splice(draggedIndex, 1); newIds.splice(targetIndex, 0, draggedId); reorderMutation.mutate(newIds); setDraggedId(null); }; const handleDelete = (link: ExternalLink) => { setDeletingLink(link); }; const confirmDelete = () => { if (deletingLink) { deleteMutation.mutate(deletingLink.id); setDeletingLink(null); } }; return ( <>

Sidebar Links

Add external links to the sidebar navigation. Drag to reorder.

{isLoading ? (
) : links && links.length > 0 ? (
{links.map((link) => { const Icon = getIconByName(link.icon); return (
handleDragStart(e, link.id)} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, link.id)} className={`flex items-center gap-3 p-3 rounded-lg bg-bambu-dark border border-bambu-dark-tertiary transition-colors ${ draggedId === link.id ? 'opacity-50' : '' }`} >
{link.name}
{link.url}
); })}
) : (

{t('externalLinks.noLinksConfigured')}

Click "Add Link" to add one

)}
{/* Add/Edit Modal */} {(showAddModal || editingLink) && ( { setShowAddModal(false); setEditingLink(null); }} /> )} {/* Delete Confirmation Modal */} {deletingLink && ( setDeletingLink(null)} /> )} ); }