diff --git a/src/app/ui/create-webhook-form.tsx b/src/app/ui/create-webhook-form.tsx index 0b66e98..4d082a7 100644 --- a/src/app/ui/create-webhook-form.tsx +++ b/src/app/ui/create-webhook-form.tsx @@ -4,6 +4,7 @@ import { submitWebhookForm } from "@/lib/actions"; import HelpTip from "@/app/ui/help-tip"; import SelectDropdown from "@/app/ui/select-dropdown"; import AttachDropdown from "./attach-dropdown"; +import WebhookTypeDropdown from "@/app/ui/webhook-type-dropdown"; import FileUpload from "@/app/ui/file-upload"; import IframePreview from "@/app/ui/iframe-preview"; import EmailInput from "@/app/ui/email-input"; @@ -12,12 +13,12 @@ import { useRouter } from "next/navigation"; import { useEffect } from "react"; import { Toast } from "flowbite-react"; import { HiCheck, HiClipboard } from "react-icons/hi"; +import { GoAlert } from "react-icons/go"; interface SubmitResponse { status: string; message: string; - webhook_id?: string; - webhook_url?: string; + data?: { webhook_id: string; webhook_url: string }; errors?: { path: string; message: string }[]; } @@ -38,8 +39,10 @@ export default function CreateWebhookForm() { const [attachment_file_ids, setAttachment_file_ids] = useState([]); const [isGenerateCertificate, setIsGenerateCertificate] = useState(false); const [showSuccessToast, setShowSuccessToast] = useState(false); - const [showCopyToast, setShowCopyToast] = useState(false); + const [showFailedToast, setShowFailedToast] = useState(false); + const [isCopied, setIsCopied] = useState(false); const [webhookUrl, setWebhookUrl] = useState(""); + const [webhookType, setWebhookType] = useState("surveycake"); const router = useRouter(); @@ -58,8 +61,12 @@ export default function CreateWebhookForm() { const onSubmit = async (event: FormEvent) => { event.preventDefault(); + setErrors({}); + setIsSubmitting(true); + if (!ref.current) return; + // Extract form data const formData = { subject: (ref.current.querySelector("[id='subject']") as HTMLInputElement).value, display_name: (ref.current.querySelector("[id='display_name']") as HTMLInputElement).value, @@ -75,34 +82,58 @@ export default function CreateWebhookForm() { bcc: bccEmails, cc: ccEmails, is_generate_certificate: isGenerateCertificate, + webhook_type: webhookType, }; - setIsSubmitting(true); try { - const response: SubmitResponse = await submitWebhookForm( + const response = await submitWebhookForm( JSON.stringify(formData), - localStorage.getItem("access_token") ?? "" + localStorage.getItem("access_token") || "" ); - if (response.status === "error" && response.errors) { + handleResponse(response); + } catch (error: any) { + console.error("Unexpected error:", error); + showToast("error", "Unexpected error occurred. Please try again."); + } finally { + setIsSubmitting(false); + } + }; + + // Helper function to handle the response + const handleResponse = (response: SubmitResponse) => { + if (response.status === "error") { + if (response.errors) { + // Handle validation errors const newErrors: { [key: string]: string } = {}; response.errors.forEach(err => { newErrors[err.path] = err.message; }); setErrors(newErrors); - setIsSubmitting(false); - return; + showToast("error", "Validation failed. Please fix the errors."); + } else { + // Handle general API errors + showToast("error", response.message || "Failed to create webhook."); } + return; + } + + // Success case + setWebhookUrl(response.data?.webhook_url || ""); + setIsCopied(false); + showToast("success", "Webhook created successfully!"); + }; - setWebhookUrl(response.webhook_url || ""); + // Helper function for showing toast notifications + const showToast = (status: "success" | "error", message: string) => { + if (status === "success") { setShowSuccessToast(true); setTimeout(() => setShowSuccessToast(false), 10000); - setErrors({}); - ref.current.reset(); - } catch (error: any) { - alert("Failed to create webhook: " + error.message); + } else { + setShowFailedToast(true); + setTimeout(() => setShowFailedToast(false), 3000); } - setIsSubmitting(false); + console.log(`[${status.toUpperCase()}] ${message}`); }; const handleHtmlSelect = (file_id: string | null, file_url: string | null) => { @@ -135,12 +166,14 @@ export default function CreateWebhookForm() { setShowAttachUpload(false); }; - // 複製功能 + const handleWebhookTypeChange = (webhook_type: string) => { + setWebhookType(webhook_type); + }; + const copyToClipboard = async (text: string) => { try { await navigator.clipboard.writeText(text); - setShowCopyToast(true); // 顯示複製成功提示 - setTimeout(() => setShowCopyToast(false), 3000); // 3秒後關閉 + setIsCopied(true); } catch (err) { console.error("Failed to copy:", err); } @@ -283,6 +316,7 @@ export default function CreateWebhookForm() { value="no" onChange={() => setIsGenerateCertificate(false)} name="inline-radio-group" + defaultChecked className="w-4 h-4 text-blue-600 bg-white border-gray-300 focus:ring-blue-500" />