From 26c83942694bf2c30b6fc283b95754d6d9263b4b Mon Sep 17 00:00:00 2001 From: The Doom Lab Date: Wed, 27 May 2026 08:56:17 -0500 Subject: [PATCH 1/2] add feedback form --- integrations/emails.tsx | 33 ++++++++++ src/core/components/FeedbackButton.tsx | 86 ++++++++++++++++++++++++++ src/core/layouts/Layout.tsx | 2 + src/core/mutations/sendFeedback.ts | 32 ++++++++++ 4 files changed, 153 insertions(+) create mode 100644 src/core/components/FeedbackButton.tsx create mode 100644 src/core/mutations/sendFeedback.ts diff --git a/integrations/emails.tsx b/integrations/emails.tsx index 31ca6d0e..53a46853 100644 --- a/integrations/emails.tsx +++ b/integrations/emails.tsx @@ -273,6 +273,39 @@ staple.helpdesk@gmail.com } } +export function createFeedbackMsg({ + fromUsername, + fromEmail, + subject, + message, +}: { + fromUsername: string + fromEmail: string + subject: string + message: string +}) { + return { + from: "STAPLE ", + to: "staple.helpdesk@gmail.com", + replyTo: fromEmail ? `${fromUsername} <${fromEmail}>` : "STAPLE App", + subject: `[Feedback] ${subject}`, + html: ` + + +
STAPLE Logo
+

Feedback from ${fromUsername}

+

Subject: ${subject}

+

Message:

+

${message.replace(/\n/g, "
")}

+
+

Sent from STAPLE by ${fromUsername} (${fromEmail})

+ + + `, + } +} + export function createEditProfileMsg(user) { return { from: "STAPLE ", diff --git a/src/core/components/FeedbackButton.tsx b/src/core/components/FeedbackButton.tsx new file mode 100644 index 00000000..9f740108 --- /dev/null +++ b/src/core/components/FeedbackButton.tsx @@ -0,0 +1,86 @@ +import { useState, useRef } from "react" +import { useMutation } from "@blitzjs/rpc" +import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline" +import sendFeedback from "src/core/mutations/sendFeedback" +import toast from "react-hot-toast" + +export const FeedbackButton = () => { + const [subject, setSubject] = useState("") + const [message, setMessage] = useState("") + const [sendFeedbackMutation, { isLoading }] = useMutation(sendFeedback) + const dialogRef = useRef(null) + + const openModal = () => dialogRef.current?.showModal() + const closeModal = () => dialogRef.current?.close() + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + try { + await sendFeedbackMutation({ subject, message }) + toast.success("Feedback sent! We'll be in touch.") + setSubject("") + setMessage("") + closeModal() + } catch { + toast.error("Failed to send feedback. Please try again.") + } + } + + return ( + <> + + + +
+

Send Feedback

+
+
+ + setSubject(e.target.value)} + required + maxLength={200} + /> +
+
+ +