Kaynağa Gözat

feat(layout): add ability to create new layout sections

Added server action to create layout sections with configuration ID and section data.
Updated LayoutConfigurationDetail component to include Add Section button and dialog
integration for creating new sections within existing configurations.
vtugulan 6 ay önce
ebeveyn
işleme
ef42296bd4

+ 31 - 0
app/actions/layout-configurations.ts

@@ -130,4 +130,35 @@ export async function deleteLayoutConfiguration(id: number) {
     console.error("Error deleting layout configuration:", error);
     return { success: false, error: "Failed to delete layout configuration" };
   }
+}
+
+// Create new layout section
+export async function createLayoutSection(
+  configurationId: number,
+  sectionData: {
+    name: string;
+    type: string;
+    sheetName: string;
+    tableName: string;
+    startingRow?: number;
+    endingRow?: number;
+  }
+) {
+  try {
+    const section = await prisma.layoutSection.create({
+      data: {
+        configurationId,
+        name: sectionData.name,
+        type: sectionData.type,
+        sheetName: sectionData.sheetName,
+        tableName: sectionData.tableName,
+        startingRow: sectionData.startingRow,
+        endingRow: sectionData.endingRow,
+      },
+    });
+    return { success: true, data: section };
+  } catch (error) {
+    console.error("Error creating layout section:", error);
+    return { success: false, error: "Failed to create layout section" };
+  }
 }

+ 202 - 0
app/components/layout-configurations/AddSectionDialog.tsx

@@ -0,0 +1,202 @@
+"use client";
+
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { createLayoutSection } from "@/app/actions/layout-configurations";
+import { Button } from "@/components/ui/button";
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+} from "@/components/ui/dialog";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Textarea } from "@/components/ui/textarea";
+import { useToast } from "@/hooks/use-toast";
+
+interface AddSectionDialogProps {
+  configurationId: number;
+  open: boolean;
+  onOpenChange: (open: boolean) => void;
+}
+
+export function AddSectionDialog({
+  configurationId,
+  open,
+  onOpenChange,
+}: AddSectionDialogProps) {
+  const router = useRouter();
+  const { toast } = useToast();
+  const [isLoading, setIsLoading] = useState(false);
+  const [formData, setFormData] = useState({
+    name: "",
+    type: "table",
+    sheetName: "",
+    tableName: "",
+    startingRow: "",
+    endingRow: "",
+  });
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    setIsLoading(true);
+
+    try {
+      const result = await createLayoutSection(configurationId, {
+        name: formData.name,
+        type: formData.type,
+        sheetName: formData.sheetName,
+        tableName: formData.tableName,
+        startingRow: formData.startingRow ? parseInt(formData.startingRow) : undefined,
+        endingRow: formData.endingRow ? parseInt(formData.endingRow) : undefined,
+      });
+
+      if (result.success) {
+        toast({
+          title: "Section added successfully",
+          description: `Section "${formData.name}" has been added to the configuration.`,
+        });
+        
+        // Reset form and close dialog
+        setFormData({
+          name: "",
+          type: "table",
+          sheetName: "",
+          tableName: "",
+          startingRow: "",
+          endingRow: "",
+        });
+        onOpenChange(false);
+        
+        // Refresh the page to show the new section
+        router.refresh();
+      } else {
+        toast({
+          title: "Error adding section",
+          description: result.error || "Failed to add section",
+          variant: "destructive",
+        });
+      }
+    } catch (error) {
+      toast({
+        title: "Error",
+        description: "An unexpected error occurred",
+        variant: "destructive",
+      });
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
+    const { name, value } = e.target;
+    setFormData((prev) => ({ ...prev, [name]: value }));
+  };
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="sm:max-w-[500px]">
+        <DialogHeader>
+          <DialogTitle>Add New Section</DialogTitle>
+          <DialogDescription>
+            Create a new section for this layout configuration
+          </DialogDescription>
+        </DialogHeader>
+        <form onSubmit={handleSubmit}>
+          <div className="grid gap-4 py-4">
+            <div className="grid gap-2">
+              <Label htmlFor="name">Section Name *</Label>
+              <Input
+                id="name"
+                name="name"
+                value={formData.name}
+                onChange={handleChange}
+                placeholder="e.g., Customer Information"
+                required
+              />
+            </div>
+
+            <div className="grid gap-2">
+              <Label htmlFor="type">Section Type *</Label>
+              <Input
+                id="type"
+                name="type"
+                value={formData.type}
+                onChange={handleChange}
+                placeholder="e.g., table, header, footer"
+                required
+              />
+            </div>
+
+            <div className="grid gap-2">
+              <Label htmlFor="sheetName">Sheet Name *</Label>
+              <Input
+                id="sheetName"
+                name="sheetName"
+                value={formData.sheetName}
+                onChange={handleChange}
+                placeholder="e.g., Sheet1"
+                required
+              />
+            </div>
+
+            <div className="grid gap-2">
+              <Label htmlFor="tableName">Table Name *</Label>
+              <Input
+                id="tableName"
+                name="tableName"
+                value={formData.tableName}
+                onChange={handleChange}
+                placeholder="e.g., customers"
+                required
+              />
+            </div>
+
+            <div className="grid grid-cols-2 gap-4">
+              <div className="grid gap-2">
+                <Label htmlFor="startingRow">Starting Row</Label>
+                <Input
+                  id="startingRow"
+                  name="startingRow"
+                  type="number"
+                  value={formData.startingRow}
+                  onChange={handleChange}
+                  placeholder="e.g., 2"
+                  min="1"
+                />
+              </div>
+              <div className="grid gap-2">
+                <Label htmlFor="endingRow">Ending Row</Label>
+                <Input
+                  id="endingRow"
+                  name="endingRow"
+                  type="number"
+                  value={formData.endingRow}
+                  onChange={handleChange}
+                  placeholder="e.g., 100"
+                  min="1"
+                />
+              </div>
+            </div>
+          </div>
+          <DialogFooter>
+            <Button
+              type="button"
+              variant="outline"
+              onClick={() => onOpenChange(false)}
+              disabled={isLoading}
+            >
+              Cancel
+            </Button>
+            <Button type="submit" disabled={isLoading}>
+              {isLoading ? "Adding..." : "Add Section"}
+            </Button>
+          </DialogFooter>
+        </form>
+      </DialogContent>
+    </Dialog>
+  );
+}

+ 10 - 1
app/components/layout-configurations/LayoutConfigurationDetail.tsx

@@ -1,7 +1,9 @@
 "use client";
 
+import { useState } from "react";
 import { useRouter } from "next/navigation";
 import { LayoutSectionCard } from "./LayoutSectionCard";
+import { AddSectionDialog } from "./AddSectionDialog";
 import { Button } from "@/components/ui/button";
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
 import { Badge } from "@/components/ui/badge";
@@ -42,6 +44,7 @@ interface LayoutConfigurationDetailProps {
 
 export function LayoutConfigurationDetail({ configuration }: LayoutConfigurationDetailProps) {
   const router = useRouter();
+  const [isDialogOpen, setIsDialogOpen] = useState(false);
 
   return (
     <div className="space-y-6">
@@ -93,7 +96,7 @@ export function LayoutConfigurationDetail({ configuration }: LayoutConfiguration
       <div className="space-y-4">
         <div className="flex justify-between items-center">
           <h2 className="text-2xl font-semibold">Sections</h2>
-          <Button size="sm">
+          <Button size="sm" onClick={() => setIsDialogOpen(true)}>
             <Plus className="h-4 w-4 mr-2" />
             Add Section
           </Button>
@@ -115,6 +118,12 @@ export function LayoutConfigurationDetail({ configuration }: LayoutConfiguration
           </div>
         )}
       </div>
+
+      <AddSectionDialog
+        configurationId={configuration.id}
+        open={isDialogOpen}
+        onOpenChange={setIsDialogOpen}
+      />
     </div>
   );
 }