Files
star-erp/resources/js/Components/Warehouse/WarehouseDialog.tsx
2025-12-30 15:03:19 +08:00

237 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 倉庫對話框元件
* 重構後:加入驗證邏輯
*/
import { useEffect, useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/Components/ui/dialog";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/Components/ui/alert-dialog";
import { Input } from "@/Components/ui/input";
import { Label } from "@/Components/ui/label";
import { Textarea } from "@/Components/ui/textarea";
import { Button } from "@/Components/ui/button";
import { Trash2 } from "lucide-react";
import { Warehouse } from "@/types/warehouse";
import { validateWarehouse } from "@/utils/validation";
import { toast } from "sonner";
interface WarehouseDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
warehouse: Warehouse | null;
onSave: (warehouse: Omit<Warehouse, "id" | "createdAt" | "updatedAt">) => void;
onDelete?: (warehouseId: string) => void;
}
export default function WarehouseDialog({
open,
onOpenChange,
warehouse,
onSave,
onDelete,
}: WarehouseDialogProps) {
const [formData, setFormData] = useState<{
code: string;
name: string;
address: string;
description: string;
}>({
code: "",
name: "",
address: "",
description: "",
});
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
useEffect(() => {
if (warehouse) {
setFormData({
code: warehouse.code,
name: warehouse.name,
address: warehouse.address || "",
description: warehouse.description || "",
});
} else {
setFormData({
code: "",
name: "",
address: "",
description: "",
});
}
}, [warehouse, open]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const validation = validateWarehouse(formData);
if (!validation.isValid) {
toast.error(validation.error);
return;
}
onSave(formData);
};
const handleDelete = () => {
if (warehouse && onDelete) {
onDelete(warehouse.id);
setShowDeleteDialog(false);
onOpenChange(false);
}
};
return (
<>
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>{warehouse ? "編輯倉庫" : "新增倉庫"}</DialogTitle>
<DialogDescription>
{warehouse ? "修改倉庫資訊" : "建立新的倉庫資訊"}
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit}>
<div className="space-y-6 py-4">
{/* 區塊 A基本資訊 */}
<div className="space-y-4">
<div className="border-b pb-2">
<h4 className="text-sm text-gray-700"></h4>
</div>
<div className="grid grid-cols-2 gap-4">
{/* 倉庫編號 */}
<div className="space-y-2">
<Label htmlFor="code">
</Label>
<Input
id="code"
value={warehouse ? formData.code : ""}
disabled={true}
placeholder={warehouse ? "" : "系統自動產生"}
className="bg-gray-100"
/>
</div>
{/* 倉庫名稱 */}
<div className="space-y-2">
<Label htmlFor="name">
<span className="text-red-500">*</span>
</Label>
<Input
id="name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="例:中央倉庫"
required
/>
</div>
</div>
</div>
{/* 區塊 B位置 */}
<div className="space-y-4">
<div className="border-b pb-2">
<h4 className="text-sm text-gray-700"></h4>
</div>
{/* 倉庫地址 */}
<div className="space-y-2">
<Label htmlFor="address">
<span className="text-red-500">*</span>
</Label>
<Input
id="address"
value={formData.address}
onChange={(e) => setFormData({ ...formData, address: e.target.value })}
placeholder="例台北市信義區信義路五段7號"
required
/>
</div>
{/* 備註說明 */}
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
value={formData.description}
onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
placeholder="其他說明"
rows={2}
className="resize-none"
/>
</div>
</div>
</div>
<DialogFooter className="gap-2">
{warehouse && onDelete && (
<Button
type="button"
onClick={() => setShowDeleteDialog(true)}
variant="outline"
className="group mr-auto border-2 border-red-600 text-red-600 hover:bg-red-600 hover:text-white"
>
<Trash2 className="mr-2 h-4 w-4 group-hover:text-white" />
</Button>
)}
<Button
type="button"
onClick={() => onOpenChange(false)}
className="button-outlined-primary"
>
</Button>
<Button type="submit" className="button-filled-primary">
{warehouse ? "更新" : "新增"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
{/* 刪除確認對話框 */}
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle></AlertDialogTitle>
<AlertDialogDescription>
{warehouse?.name}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
onClick={handleDelete}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
}