"use client"; import React from "react"; import { cn } from "@/lib/utils"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb"; import { Separator } from "@/components/ui/separator"; import { Loader2, AlertCircle, CheckCircle } from "lucide-react"; import { AdminPanelConfig, TabConfig } from "@/types/admin-panel"; import { useAdminPanel } from "@/hooks/use-admin-panel"; import { AdminSection } from "./admin-section"; import { SiteHeader } from "@/app/admin/site-header"; interface AdminPanelProps { config: AdminPanelConfig; initialValues?: Record; onSubmit?: (values: Record) => Promise; className?: string; // Permission checker function hasPermission?: (permission: string) => boolean; } export function AdminPanel({ config, initialValues, onSubmit, className, hasPermission = () => true }: AdminPanelProps) { const [activeTab, setActiveTab] = React.useState(() => { // Find first accessible tab const firstAccessibleTab = config.tabs.find(tab => !tab.disabled && (!tab.permissions || tab.permissions.some(p => hasPermission(p))) ); return firstAccessibleTab?.id || config.tabs[0]?.id || ""; }); const { state, actions, helpers } = useAdminPanel({ config, initialValues, onSubmit }); // Filter tabs based on permissions const visibleTabs = config.tabs.filter(tab => !tab.permissions || tab.permissions.some(p => hasPermission(p)) ); // Get current tab const currentTab = visibleTabs.find(tab => tab.id === activeTab); // Filter sections based on permissions const getVisibleSections = (tab: TabConfig) => { return tab.sections.filter(section => !section.permissions || section.permissions.some(p => hasPermission(p)) ); }; // Handle save with loading state const handleSave = async () => { try { await actions.save(); } catch (error) { console.error('Save failed:', error); // You might want to show a toast notification here } }; // Render header actions const renderHeaderActions = () => { const actions = config.header.actions || []; return actions .filter(action => !action.permissions || action.permissions.some(p => hasPermission(p))) .map(action => ( )); }; // Render breadcrumbs const renderBreadcrumbs = () => { if (!config.header.breadcrumbs) return null; return ({ label: crumb.label, href: crumb.href || "" }))} /> }; // Render status indicators const renderStatusIndicators = () => { const indicators = []; // Loading indicator if (state.loading) { indicators.push( 加载中 ); } // Saving indicator if (state.saving) { indicators.push( 保存中 ); } // Dirty state indicator if (helpers.isDirty() && !state.saving) { indicators.push( 有未保存的更改 ); } // Valid state indicator if (!helpers.isDirty() && helpers.isValid()) { indicators.push( 已保存 ); } // Validation errors indicator if (Object.keys(state.errors).length > 0) { indicators.push( {Object.keys(state.errors).length} 个错误 ); } return indicators; }; // Compute stable grid columns class to avoid Tailwind purge of dynamic classes const gridColsMap: Record = { 1: "grid-cols-1", 2: "grid-cols-2", 3: "grid-cols-3", 4: "grid-cols-4", 5: "grid-cols-5", 6: "grid-cols-6", }; const gridColsClass = gridColsMap[Math.min(visibleTabs.length, 6)] || "grid-cols-6"; return (
{renderBreadcrumbs()}

{config.header.title}

{config.header.description && (

{config.header.description}

)}
{/* Status indicators */} {renderStatusIndicators()} {/* Header actions */} {renderHeaderActions()} {/* Save button */} {onSubmit && ( )}
{config.theme?.layout === "sidebar" ? ( // Sidebar layout
{/* Sidebar */}
{visibleTabs.map((tab) => ( ))}
{/* Content */}
{currentTab && (
{getVisibleSections(currentTab).map((section) => ( { }} // Could implement field-level validation /> ))}
)}
) : ( // Tabs layout (default) {/* Tab Navigation */} {visibleTabs.map((tab) => ( {tab.icon} {tab.title} {tab.badge && ( {tab.badge} )} ))} {/* Tab Content */} {visibleTabs.map((tab) => ( {getVisibleSections(tab).map((section) => ( { }} // Could implement field-level validation /> ))} ))} )}
); }