summaryrefslogtreecommitdiff
path: root/lib/menu-v2/components/edit-node-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/menu-v2/components/edit-node-dialog.tsx')
-rw-r--r--lib/menu-v2/components/edit-node-dialog.tsx215
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/menu-v2/components/edit-node-dialog.tsx b/lib/menu-v2/components/edit-node-dialog.tsx
new file mode 100644
index 00000000..9631a611
--- /dev/null
+++ b/lib/menu-v2/components/edit-node-dialog.tsx
@@ -0,0 +1,215 @@
+"use client";
+
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Textarea } from "@/components/ui/textarea";
+import { Switch } from "@/components/ui/switch";
+import type { MenuTreeNode, UpdateNodeInput } from "../types";
+
+interface EditNodeDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ node: MenuTreeNode | null;
+ onSave: (nodeId: number, data: UpdateNodeInput) => Promise<void>;
+}
+
+interface FormData {
+ titleKo: string;
+ titleEn: string;
+ descriptionKo: string;
+ descriptionEn: string;
+ scrId: string;
+ isActive: boolean;
+}
+
+export function EditNodeDialog({
+ open,
+ onOpenChange,
+ node,
+ onSave,
+}: EditNodeDialogProps) {
+ const {
+ register,
+ handleSubmit,
+ reset,
+ setValue,
+ watch,
+ formState: { isSubmitting },
+ } = useForm<FormData>({
+ defaultValues: {
+ titleKo: "",
+ titleEn: "",
+ descriptionKo: "",
+ descriptionEn: "",
+ scrId: "",
+ isActive: true,
+ },
+ });
+
+ const isActive = watch("isActive");
+
+ useEffect(() => {
+ if (node) {
+ reset({
+ titleKo: node.titleKo,
+ titleEn: node.titleEn || "",
+ descriptionKo: node.descriptionKo || "",
+ descriptionEn: node.descriptionEn || "",
+ scrId: node.scrId || "",
+ isActive: node.isActive,
+ });
+ }
+ }, [node, reset]);
+
+ const onSubmit = async (data: FormData) => {
+ if (!node) return;
+
+ await onSave(node.id, {
+ titleKo: data.titleKo,
+ titleEn: data.titleEn || undefined,
+ descriptionKo: data.descriptionKo || undefined,
+ descriptionEn: data.descriptionEn || undefined,
+ scrId: data.scrId || undefined,
+ isActive: data.isActive,
+ });
+
+ onOpenChange(false);
+ };
+
+ const getTypeLabel = () => {
+ switch (node?.nodeType) {
+ case "menu_group":
+ return "Menu Group";
+ case "group":
+ return "Group";
+ case "menu":
+ return "Menu";
+ case "additional":
+ return "Additional Menu";
+ default:
+ return "Node";
+ }
+ };
+
+ const showMenuFields = node?.nodeType === "menu" || node?.nodeType === "additional";
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-lg">
+ <DialogHeader>
+ <DialogTitle>Edit {getTypeLabel()}</DialogTitle>
+ <DialogDescription>
+ {node?.menuPath && (
+ <span className="text-xs text-muted-foreground">{node.menuPath}</span>
+ )}
+ </DialogDescription>
+ </DialogHeader>
+
+ <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
+ <div className="grid gap-4">
+ {/* Korean Name */}
+ <div className="grid gap-2">
+ <Label htmlFor="titleKo">Name (Korean) *</Label>
+ <Input
+ id="titleKo"
+ {...register("titleKo", { required: true })}
+ placeholder="Project List"
+ />
+ </div>
+
+ {/* English Name */}
+ <div className="grid gap-2">
+ <Label htmlFor="titleEn">Name (English)</Label>
+ <Input
+ id="titleEn"
+ {...register("titleEn")}
+ placeholder="Project List"
+ />
+ </div>
+
+ {/* Korean Description */}
+ {showMenuFields && (
+ <div className="grid gap-2">
+ <Label htmlFor="descriptionKo">Description (Korean)</Label>
+ <Textarea
+ id="descriptionKo"
+ {...register("descriptionKo")}
+ placeholder="Project list from MDG (C)"
+ rows={2}
+ />
+ </div>
+ )}
+
+ {/* English Description */}
+ {showMenuFields && (
+ <div className="grid gap-2">
+ <Label htmlFor="descriptionEn">Description (English)</Label>
+ <Textarea
+ id="descriptionEn"
+ {...register("descriptionEn")}
+ placeholder="Project list from MDG (C)"
+ rows={2}
+ />
+ </div>
+ )}
+
+ {/* Permission SCR_ID */}
+ {showMenuFields && (
+ <div className="grid gap-2">
+ <Label htmlFor="scrId">Permission SCR_ID (EVCP only)</Label>
+ <Input
+ id="scrId"
+ {...register("scrId")}
+ placeholder="SCR_001"
+ />
+ <p className="text-xs text-muted-foreground">
+ Linked with Oracle DB SCR_ID. If empty, auto-matched by URL.
+ </p>
+ </div>
+ )}
+
+ {/* Active Status */}
+ <div className="flex items-center justify-between">
+ <div className="space-y-0.5">
+ <Label htmlFor="isActive">Show in Menu</Label>
+ <p className="text-xs text-muted-foreground">
+ When disabled, hidden from the navigation menu.
+ </p>
+ </div>
+ <Switch
+ id="isActive"
+ checked={isActive}
+ onCheckedChange={(checked) => setValue("isActive", checked)}
+ />
+ </div>
+ </div>
+
+ <DialogFooter>
+ <Button
+ type="button"
+ variant="outline"
+ onClick={() => onOpenChange(false)}
+ >
+ Cancel
+ </Button>
+ <Button type="submit" disabled={isSubmitting}>
+ {isSubmitting ? "Saving..." : "Save"}
+ </Button>
+ </DialogFooter>
+ </form>
+ </DialogContent>
+ </Dialog>
+ );
+}
+