Files
star-erp/resources/js/Components/Warehouse/WarehouseDialog.tsx

258 lines
8.1 KiB
TypeScript
Raw Normal View History

2025-12-30 15:03:19 +08:00
/**
*
*
*/
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;
is_sellable: boolean;
2025-12-30 15:03:19 +08:00
}>({
code: "",
name: "",
address: "",
description: "",
is_sellable: true,
2025-12-30 15:03:19 +08:00
});
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
useEffect(() => {
if (warehouse) {
setFormData({
code: warehouse.code,
name: warehouse.name,
address: warehouse.address || "",
description: warehouse.description || "",
is_sellable: warehouse.is_sellable ?? true,
2025-12-30 15:03:19 +08:00
});
} else {
setFormData({
code: "",
name: "",
address: "",
description: "",
is_sellable: true,
2025-12-30 15:03:19 +08:00
});
}
}, [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>
{/* 銷售設定 */}
<div className="space-y-4">
<div className="border-b pb-2">
<h4 className="text-sm text-gray-700"></h4>
</div>
<div className="flex items-center space-x-2">
<input
type="checkbox"
id="is_sellable"
className="h-4 w-4 rounded border-gray-300 text-primary-main focus:ring-primary-main"
checked={formData.is_sellable}
onChange={(e) => setFormData({ ...formData, is_sellable: e.target.checked })}
/>
<Label htmlFor="is_sellable"></Label>
</div>
</div>
2025-12-30 15:03:19 +08:00
{/* 區塊 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="mr-auto button-outlined-error"
2025-12-30 15:03:19 +08:00
>
<Trash2 className="mr-2 h-4 w-4" />
2025-12-30 15:03:19 +08:00
</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 >
2025-12-30 15:03:19 +08:00
{/* 刪除確認對話框 */}
< AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog} >
2025-12-30 15:03:19 +08:00
<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 >
2025-12-30 15:03:19 +08:00
</>
);
}