From 89d55784dee8e966a220c5074655fcf744250948 Mon Sep 17 00:00:00 2001 From: chungchihhan Date: Mon, 16 Dec 2024 11:58:21 +0800 Subject: [PATCH 1/4] feat: add a dropdown for webhook_type | SCRUM-189 --- src/app/ui/create-webhook-form.tsx | 16 ++++++ src/app/ui/webhook-type-dropdown.tsx | 86 ++++++++++++++++++++++++++++ src/lib/actions.ts | 1 + 3 files changed, 103 insertions(+) create mode 100644 src/app/ui/webhook-type-dropdown.tsx diff --git a/src/app/ui/create-webhook-form.tsx b/src/app/ui/create-webhook-form.tsx index 0b66e98..e6b52b3 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"; @@ -40,6 +41,7 @@ export default function CreateWebhookForm() { const [showSuccessToast, setShowSuccessToast] = useState(false); const [showCopyToast, setShowCopyToast] = useState(false); const [webhookUrl, setWebhookUrl] = useState(""); + const [webhookType, setWebhookType] = useState("surveycake"); const router = useRouter(); @@ -75,6 +77,7 @@ export default function CreateWebhookForm() { bcc: bccEmails, cc: ccEmails, is_generate_certificate: isGenerateCertificate, + webhook_type: webhookType, }; setIsSubmitting(true); @@ -135,6 +138,10 @@ export default function CreateWebhookForm() { setShowAttachUpload(false); }; + const handleWebhookTypeChange = (webhook_type: string) => { + setWebhookType(webhook_type); + }; + // 複製功能 const copyToClipboard = async (text: string) => { try { @@ -448,6 +455,15 @@ export default function CreateWebhookForm() { /> {errors.iv_key &&

{errors.iv_key}

} +
+ + +
diff --git a/src/app/ui/webhook-type-dropdown.tsx b/src/app/ui/webhook-type-dropdown.tsx new file mode 100644 index 0000000..12f2db7 --- /dev/null +++ b/src/app/ui/webhook-type-dropdown.tsx @@ -0,0 +1,86 @@ +"use client"; +import React, { useState, useRef, useEffect } from "react"; + +interface WebhookTypeDropdownProps { + onSelect: (type: string) => void; +} + +export default function WebhookTypeDropdown({ onSelect }: WebhookTypeDropdownProps) { + const [isOpen, setIsOpen] = useState(false); + const [selectedType, setSelectedType] = useState("surveycake"); + const dropdownRef = useRef(null); + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + + const toggleDropdown = () => { + setIsOpen(!isOpen); + }; + + const handleSelect = (type: string) => { + setSelectedType(type); + onSelect(type); // Pass the selected type to the parent component + setIsOpen(false); + }; + + return ( +
+
+ +
+ + {isOpen && ( +
+
+
handleSelect("surveycake")} + > + SurveyCake +
+
handleSelect("slack")} + > + Slack +
+
+
+ )} +
+ ); +} diff --git a/src/lib/actions.ts b/src/lib/actions.ts index abdfbd4..7e5d385 100644 --- a/src/lib/actions.ts +++ b/src/lib/actions.ts @@ -45,6 +45,7 @@ const webhookFormSchema = z.object({ hash_key: z.string().min(1, "Hash key is required"), iv_key: z.string().min(1, "IV key is required"), webhook_name: z.string().min(1, "Webhook name is required"), + webhook_type: z.string().min(1, "Webhook type is required"), }); export async function submitForm(data: string, access_token: string) { From 98f8b7f920ec29d900e5ce95cdaa1146cf70cbb3 Mon Sep 17 00:00:00 2001 From: chungchihhan Date: Mon, 16 Dec 2024 15:01:00 +0800 Subject: [PATCH 2/4] style: change the toast for better looking | SCRUM-189 --- src/app/ui/create-webhook-form.tsx | 45 +++++++++++++----------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/app/ui/create-webhook-form.tsx b/src/app/ui/create-webhook-form.tsx index e6b52b3..97c954b 100644 --- a/src/app/ui/create-webhook-form.tsx +++ b/src/app/ui/create-webhook-form.tsx @@ -39,7 +39,7 @@ 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 [isCopied, setIsCopied] = useState(false); const [webhookUrl, setWebhookUrl] = useState(""); const [webhookType, setWebhookType] = useState("surveycake"); @@ -99,9 +99,10 @@ export default function CreateWebhookForm() { setWebhookUrl(response.webhook_url || ""); setShowSuccessToast(true); + setIsCopied(false); setTimeout(() => setShowSuccessToast(false), 10000); setErrors({}); - ref.current.reset(); + // ref.current.reset(); } catch (error: any) { alert("Failed to create webhook: " + error.message); } @@ -142,12 +143,10 @@ export default function CreateWebhookForm() { 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); } @@ -290,6 +289,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" />