Skip to content

Instantly share code, notes, and snippets.

@domtaylor
Created April 10, 2026 06:11
Show Gist options
  • Select an option

  • Save domtaylor/ae0f7c546fe55c10fd10f0977e3e4f68 to your computer and use it in GitHub Desktop.

Select an option

Save domtaylor/ae0f7c546fe55c10fd10f0977e3e4f68 to your computer and use it in GitHub Desktop.
Sentry - App Feedback
export default function AppFeedback() {
const data = useLoaderData();
const [searchParams] = useSearchParams();
const associatedEventId = searchParams.get("eventId") || undefined;
const [name, setName] = useState(data.defaultName || "");
const [email, setEmail] = useState(data.email || "");
const [message, setMessage] = useState("");
const [submitting, setSubmitting] = useState(false);
const [banner, setBanner] = useState(null);
const handleSubmit = useCallback(
async (event) => {
event.preventDefault();
setBanner(null);
const trimmedMessage = message.trim();
if (!trimmedMessage) {
setBanner({ status: "critical", message: "Please enter your feedback." });
return;
}
const trimmedEmail = email.trim();
if (!trimmedEmail) {
setBanner({ status: "critical", message: "Please enter your email." });
return;
}
setSubmitting(true);
try {
Sentry.captureFeedback({
name: name.trim() || "Anonymous",
email: trimmedEmail,
message: trimmedMessage,
url: typeof window !== "undefined" ? window.location.href : undefined,
associatedEventId: associatedEventId || undefined,
tags: {
shop: data.shop || "unknown",
},
source: "polaris-feedback",
});
await Sentry.flush(2000);
setMessage("");
setBanner({
status: "success",
message: "Thanks — your feedback was sent.",
});
} catch (e) {
console.error("[app.feedback] captureFeedback failed:", e);
setBanner({
status: "critical",
message: "Could not send feedback. Try again in a moment.",
});
} finally {
setSubmitting(false);
}
},
[name, email, message, associatedEventId, data.shop]
);
if (data.error && !data.shop) {
return (
<Page title="Send feedback">
<Layout>
<Layout.Section>
<Banner status="critical">{data.error}</Banner>
</Layout.Section>
</Layout>
</Page>
);
}
return (
<Page title="Send feedback" subtitle="Product feedback and bug reports">
<Layout>
<Layout.Section>
<Card sectioned>
<BlockStack gap="400">
<Text as="h2" variant="headingMd">
Tell us what you think
</Text>
<Text as="p" variant="bodyMd" color="subdued">
This form sends feedback to our team. For account or billing help, use
Support instead.
</Text>
{associatedEventId ? (
<Banner status="info">
This feedback will be linked to error report{" "}
<code style={{ fontSize: "0.85em" }}>{associatedEventId}</code>.
</Banner>
) : null}
{banner?.status === "success" ? (
<Banner status="success" onDismiss={() => setBanner(null)}>
{banner.message}
</Banner>
) : null}
{banner?.status === "critical" ? (
<Banner status="critical" onDismiss={() => setBanner(null)}>
{banner.message}
</Banner>
) : null}
<form onSubmit={handleSubmit} noValidate>
<FormLayout>
<TextField
label="Name"
value={name}
onChange={setName}
autoComplete="name"
helpText="Optional"
/>
<TextField
label="Email"
type="email"
value={email}
onChange={setEmail}
autoComplete="email"
requiredIndicator
helpText="We may follow up about this report"
/>
<TextField
label="Feedback"
value={message}
onChange={setMessage}
multiline={6}
requiredIndicator
placeholder="What happened, what did you expect, and steps to reproduce if it’s a bug…"
/>
<InlineStack gap="400" align="end">
<Button submit primary loading={submitting} disabled={submitting}>
Send feedback
</Button>
</InlineStack>
</FormLayout>
</form>
</BlockStack>
</Card>
</Layout.Section>
</Layout>
</Page>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment