| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- "use client";
- import { useEffect, useState } from "react";
- import { useRouter } from "next/navigation";
- import { getLayoutConfigurations, deleteLayoutConfiguration } from "@/app/actions/layout-configurations";
- import { Button } from "@/components/ui/button";
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
- import { Badge } from "@/components/ui/badge";
- import { Skeleton } from "@/components/ui/skeleton";
- import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
- import { toast } from "@/hooks/use-toast";
- import { Trash2, Eye, Edit, RefreshCw } from "lucide-react";
- interface LayoutConfiguration {
- id: number;
- name: string;
- sections: LayoutSection[];
- createdAt: string;
- updatedAt: string;
- }
- interface LayoutSection {
- id: number;
- name: string;
- type: string;
- sheetName: string;
- fields: LayoutSectionField[];
- }
- interface LayoutSectionField {
- id: number;
- name: string;
- dataType: string;
- cellPosition: string;
- }
- export function LayoutConfigurationsTable() {
- const [configurations, setConfigurations] = useState<LayoutConfiguration[]>([]);
- const [loading, setLoading] = useState(true);
- const [isRefreshing, setIsRefreshing] = useState(false);
- const router = useRouter();
- useEffect(() => {
- loadConfigurations();
- }, []);
- async function loadConfigurations() {
- try {
- const result = await getLayoutConfigurations();
- if (result.success) {
- const configurations = (result.data || []).map(config => ({
- ...config,
- createdAt: config.createdAt instanceof Date ? config.createdAt.toISOString() : String(config.createdAt),
- updatedAt: config.updatedAt instanceof Date ? config.updatedAt.toISOString() : String(config.updatedAt),
- }));
- setConfigurations(configurations);
- } else {
- toast({
- title: "Error",
- description: result.error,
- variant: "destructive",
- });
- }
- } catch {
- toast({
- title: "Error",
- description: "Failed to load configurations",
- variant: "destructive",
- });
- } finally {
- setLoading(false);
- setIsRefreshing(false);
- }
- }
- async function refreshConfigurations() {
- setIsRefreshing(true);
- await loadConfigurations();
- }
- async function handleDelete(id: number) {
- try {
- const result = await deleteLayoutConfiguration(id);
- if (result.success) {
- toast({
- title: "Success",
- description: "Configuration deleted successfully",
- });
- loadConfigurations();
- } else {
- toast({
- title: "Error",
- description: result.error,
- variant: "destructive",
- });
- }
- } catch {
- toast({
- title: "Error",
- description: "Failed to delete configuration",
- variant: "destructive",
- });
- }
- }
- if (loading) {
- return (
- <div className="p-4 space-y-4">
- {[...Array(3)].map((_, i) => (
- <Card key={i}>
- <CardHeader>
- <Skeleton className="h-6 w-48" />
- <Skeleton className="h-4 w-32" />
- </CardHeader>
- <CardContent>
- <Skeleton className="h-4 w-full" />
- </CardContent>
- </Card>
- ))}
- </div>
- );
- }
- if (configurations.length === 0) {
- return (
- <div className="p-8 text-center">
- <p className="text-muted-foreground mb-4">No layout configurations found</p>
- <Button
- variant="outline"
- size="sm"
- onClick={refreshConfigurations}
- disabled={isRefreshing}
- className="flex items-center gap-2 mx-auto"
- >
- <RefreshCw className={`h-4 w-4 ${isRefreshing ? 'animate-spin' : ''}`} />
- {isRefreshing ? "Refreshing..." : "Refresh"}
- </Button>
- </div>
- );
- }
- return (
- <div className="p-4 space-y-4">
- <div className="flex justify-end">
- <Button
- variant="outline"
- size="sm"
- onClick={refreshConfigurations}
- disabled={isRefreshing}
- className="flex items-center gap-2"
- >
- <RefreshCw className={`h-4 w-4 ${isRefreshing ? 'animate-spin' : ''}`} />
- {isRefreshing ? "Refreshing..." : "Refresh"}
- </Button>
- </div>
- {configurations.map((config) => (
- <Card key={config.id} className="hover:shadow-md transition-shadow">
- <CardHeader>
- <div className="flex justify-between items-start">
- <div>
- <CardTitle className="text-xl">{config.name}</CardTitle>
- <CardDescription>
- Created: {new Date(config.createdAt).toLocaleDateString()}
- </CardDescription>
- </div>
- <div className="flex gap-2">
- <Button
- variant="ghost"
- size="sm"
- onClick={() => router.push(`/layout-configurations/${config.id}`)}
- >
- <Eye className="h-4 w-4" />
- </Button>
- <Button
- variant="ghost"
- size="sm"
- onClick={() => router.push(`/layout-configurations/${config.id}/edit`)}
- >
- <Edit className="h-4 w-4" />
- </Button>
- <AlertDialog>
- <AlertDialogTrigger asChild>
- <Button variant="ghost" size="sm" className="text-destructive">
- <Trash2 className="h-4 w-4" />
- </Button>
- </AlertDialogTrigger>
- <AlertDialogContent>
- <AlertDialogHeader>
- <AlertDialogTitle>Delete Configuration</AlertDialogTitle>
- <AlertDialogDescription>
- Are you sure you want to delete {config.name}? This action cannot be undone.
- </AlertDialogDescription>
- </AlertDialogHeader>
- <AlertDialogFooter>
- <AlertDialogCancel>Cancel</AlertDialogCancel>
- <AlertDialogAction
- onClick={() => handleDelete(config.id)}
- className="bg-destructive text-destructive-foreground"
- >
- Delete
- </AlertDialogAction>
- </AlertDialogFooter>
- </AlertDialogContent>
- </AlertDialog>
- </div>
- </div>
- </CardHeader>
- <CardContent>
- <div className="flex items-center gap-4">
- <Badge variant="secondary">
- {config.sections.length} sections
- </Badge>
- <Badge variant="outline">
- {config.sections.reduce((total, section) => total + section.fields.length, 0)} fields
- </Badge>
- </div>
- </CardContent>
- </Card>
- ))}
- </div>
- );
- }
|