|
|
@@ -0,0 +1,245 @@
|
|
|
+"use client";
|
|
|
+
|
|
|
+import { useState, useEffect, useCallback } from "react";
|
|
|
+import { useParams, useRouter } from "next/navigation";
|
|
|
+import { Button } from "@/components/ui/button";
|
|
|
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
+import { Badge } from "@/components/ui/badge";
|
|
|
+import { Plus, ArrowLeft, Edit, Trash2 } from "lucide-react";
|
|
|
+import { Skeleton } from "@/components/ui/skeleton";
|
|
|
+import { AddFieldDialog } from "@/app/components/layout-configurations/AddFieldDialog";
|
|
|
+import { EditFieldDialog } from "@/app/components/layout-configurations/EditFieldDialog";
|
|
|
+import { DeleteFieldDialog } from "@/app/components/layout-configurations/DeleteFieldDialog";
|
|
|
+import { getLayoutSectionFields, getSection } from "@/app/actions/layout-configurations";
|
|
|
+
|
|
|
+interface LayoutSectionField {
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+ dataType: string;
|
|
|
+ dataTypeFormat: string | null;
|
|
|
+ cellPosition: string;
|
|
|
+ importTableColumnName: string;
|
|
|
+ importColumnOrderNumber: number;
|
|
|
+}
|
|
|
+
|
|
|
+interface LayoutSection {
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+ type: string;
|
|
|
+ sheetName: string;
|
|
|
+ tableName: string;
|
|
|
+}
|
|
|
+
|
|
|
+export default function SectionFieldsPage() {
|
|
|
+ const params = useParams();
|
|
|
+ const router = useRouter();
|
|
|
+ const sectionId = parseInt(params.id as string);
|
|
|
+
|
|
|
+ const [section, setSection] = useState<LayoutSection | null>(null);
|
|
|
+ const [fields, setFields] = useState<LayoutSectionField[]>([]);
|
|
|
+ const [loading, setLoading] = useState(true);
|
|
|
+ const [addDialogOpen, setAddDialogOpen] = useState(false);
|
|
|
+ const [editDialogOpen, setEditDialogOpen] = useState(false);
|
|
|
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
|
+ const [selectedField, setSelectedField] = useState<LayoutSectionField | null>(null);
|
|
|
+
|
|
|
+ const loadSectionData = useCallback(async () => {
|
|
|
+ try {
|
|
|
+ setLoading(true);
|
|
|
+ const [sectionData, fieldsData] = await Promise.all([
|
|
|
+ getSection(sectionId),
|
|
|
+ getLayoutSectionFields(sectionId)
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (sectionData.success && sectionData.data) {
|
|
|
+ setSection(sectionData.data);
|
|
|
+ } else {
|
|
|
+ setSection(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fieldsData.success && fieldsData.data) {
|
|
|
+ setFields(fieldsData.data);
|
|
|
+ } else {
|
|
|
+ setFields([]);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Error loading section data:", error);
|
|
|
+ } finally {
|
|
|
+ setLoading(false);
|
|
|
+ }
|
|
|
+ }, [sectionId]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ loadSectionData();
|
|
|
+ }, [sectionId, loadSectionData]);
|
|
|
+
|
|
|
+ const handleFieldAdded = () => {
|
|
|
+ loadSectionData();
|
|
|
+ setAddDialogOpen(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleFieldUpdated = () => {
|
|
|
+ loadSectionData();
|
|
|
+ setEditDialogOpen(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleFieldDeleted = () => {
|
|
|
+ loadSectionData();
|
|
|
+ setDeleteDialogOpen(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const openEditDialog = (field: LayoutSectionField) => {
|
|
|
+ setSelectedField(field);
|
|
|
+ setEditDialogOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const openDeleteDialog = (field: LayoutSectionField) => {
|
|
|
+ setSelectedField(field);
|
|
|
+ setDeleteDialogOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ if (loading) {
|
|
|
+ return (
|
|
|
+ <div className="container mx-auto py-6 space-y-6">
|
|
|
+ <Skeleton className="h-8 w-64" />
|
|
|
+ <Skeleton className="h-32 w-full" />
|
|
|
+ <Skeleton className="h-64 w-full" />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!section) {
|
|
|
+ return (
|
|
|
+ <div className="container mx-auto py-6">
|
|
|
+ <Card>
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <p className="text-center text-muted-foreground">Section not found</p>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="container mx-auto py-6 space-y-6">
|
|
|
+ <div className="flex items-center gap-4">
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ onClick={() => router.back()}
|
|
|
+ >
|
|
|
+ <ArrowLeft className="h-4 w-4 mr-2" />
|
|
|
+ Back
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Card>
|
|
|
+ <CardHeader>
|
|
|
+ <div className="flex justify-between items-start">
|
|
|
+ <div>
|
|
|
+ <CardTitle>Section: {section.name}</CardTitle>
|
|
|
+ <CardDescription>
|
|
|
+ Manage fields for this section in the layout configuration
|
|
|
+ </CardDescription>
|
|
|
+ </div>
|
|
|
+ <div className="flex gap-2">
|
|
|
+ <Badge variant="secondary">{fields.length} fields</Badge>
|
|
|
+ <Badge variant="outline">{section.type}</Badge>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="grid gap-4">
|
|
|
+ <div>
|
|
|
+ <span className="font-medium">Sheet:</span> {section.sheetName}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <span className="font-medium">Table:</span> {section.tableName}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ <div className="space-y-4">
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <h2 className="text-2xl font-semibold">Section Fields</h2>
|
|
|
+ <Button size="sm" onClick={() => setAddDialogOpen(true)}>
|
|
|
+ <Plus className="h-4 w-4 mr-2" />
|
|
|
+ Add Field
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {fields.length === 0 ? (
|
|
|
+ <Card>
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <p className="text-center text-muted-foreground">
|
|
|
+ No fields found for this section
|
|
|
+ </p>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ ) : (
|
|
|
+ <div className="grid gap-4">
|
|
|
+ {fields.map((field) => (
|
|
|
+ <Card key={field.id} className="hover:shadow-md transition-shadow">
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="flex justify-between items-start">
|
|
|
+ <div className="space-y-2">
|
|
|
+ <div>
|
|
|
+ <span className="font-medium">{field.name}</span>
|
|
|
+ <Badge variant="outline" className="ml-2 text-xs">
|
|
|
+ {field.dataType}
|
|
|
+ </Badge>
|
|
|
+ </div>
|
|
|
+ <div className="text-sm text-muted-foreground">
|
|
|
+ <div>Position: {field.cellPosition}</div>
|
|
|
+ <div>Column: {field.importTableColumnName}</div>
|
|
|
+ <div>Order: {field.importColumnOrderNumber}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className="flex gap-2">
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ onClick={() => openEditDialog(field)}
|
|
|
+ >
|
|
|
+ <Edit className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ onClick={() => openDeleteDialog(field)}
|
|
|
+ >
|
|
|
+ <Trash2 className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <AddFieldDialog
|
|
|
+ sectionId={sectionId}
|
|
|
+ open={addDialogOpen}
|
|
|
+ onOpenChange={setAddDialogOpen}
|
|
|
+ onSuccess={handleFieldAdded}
|
|
|
+ />
|
|
|
+
|
|
|
+ <EditFieldDialog
|
|
|
+ field={selectedField}
|
|
|
+ open={editDialogOpen}
|
|
|
+ onOpenChange={setEditDialogOpen}
|
|
|
+ onSuccess={handleFieldUpdated}
|
|
|
+ />
|
|
|
+
|
|
|
+ <DeleteFieldDialog
|
|
|
+ field={selectedField}
|
|
|
+ open={deleteDialogOpen}
|
|
|
+ onOpenChange={setDeleteDialogOpen}
|
|
|
+ onSuccess={handleFieldDeleted}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|