Skip to content

Commit 04862de

Browse files
committed
feat: add feedback collection UI to navigation (#7895)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a new feature for collecting user feedback within the application. It implements feedback submission forms in both desktop and mobile components, capturing user feedback and sending it to PostHog for analysis. ### Detailed summary - Added `reportProductFeedback` function in `report.ts` to handle feedback submissions. - Implemented feedback submission in the `SecondaryNavLinks` component. - Added feedback dropdown with a form in `SecondaryNavLinks`. - Integrated feedback functionality in the `MobileBurgerMenuButton` component. - Included success notifications using `toast` for feedback submissions in both components. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Replaced external Feedback link with an in-app feedback panel in the header and mobile menu. * Panel includes a textarea (max 1000 chars), Cancel and Submit actions; Submit is disabled when empty, shows a success message, clears input and closes the panel. * Adds an in-panel “Contact support” link for technical issues and preserves existing header controls. * **Style** * Expandable/collapsible feedback UI with visual indicators, improved positioning and mobile menu scrolling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent ea46572 commit 04862de

File tree

3 files changed

+230
-17
lines changed

3 files changed

+230
-17
lines changed

apps/dashboard/src/@/analytics/report.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,3 +547,27 @@ export function reportChainInfraRpcOmissionAgreed(properties: {
547547
}) {
548548
posthog.capture("chain infra checkout rpc omission agreed", properties);
549549
}
550+
551+
// ----------------------------
552+
// FEEDBACK
553+
// ----------------------------
554+
555+
/**
556+
* ### Why do we need to report this event?
557+
* - To track user feedback and sentiment about the product
558+
* - To identify common issues or feature requests
559+
* - To measure user satisfaction and engagement
560+
* - To prioritize product improvements based on user input
561+
*
562+
* ### Who is responsible for this event?
563+
* @gisellechacon
564+
*/
565+
export function reportProductFeedback(properties: {
566+
feedback: string;
567+
source: "desktop" | "mobile";
568+
}) {
569+
posthog.capture("product feedback submitted", {
570+
feedback: properties.feedback,
571+
source: properties.source,
572+
});
573+
}

apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
"use client";
2+
13
import Link from "next/link";
24
import type React from "react";
5+
import { useState } from "react";
6+
import { toast } from "sonner";
37
import type { ThirdwebClient } from "thirdweb";
8+
import { reportProductFeedback } from "@/analytics/report";
49
import { NotificationsButton } from "@/components/notifications/notification-button";
10+
import { NavLink } from "@/components/ui/NavLink";
511
import type { Account } from "@/hooks/useApi";
612
import { AccountButton } from "./account-button.client";
713
import { ResourcesDropdownButton } from "./ResourcesDropdownButton";
@@ -31,6 +37,32 @@ export function SecondaryNav(props: {
3137
}
3238

3339
export function SecondaryNavLinks() {
40+
const [showFeedbackDropdown, setShowFeedbackDropdown] = useState(false);
41+
const [modalFeedback, setModalFeedback] = useState("");
42+
43+
const handleModalSubmit = (e?: React.FormEvent) => {
44+
e?.preventDefault();
45+
46+
// Report feedback to PostHog
47+
reportProductFeedback({
48+
feedback: modalFeedback,
49+
source: "desktop",
50+
});
51+
52+
// Show success notification
53+
toast.success("Feedback submitted successfully!", {
54+
description: "Thank you for your feedback. We'll review it shortly.",
55+
});
56+
57+
setModalFeedback("");
58+
setShowFeedbackDropdown(false);
59+
};
60+
61+
const handleModalCancel = () => {
62+
setModalFeedback("");
63+
setShowFeedbackDropdown(false);
64+
};
65+
3466
return (
3567
<div className="flex items-center gap-6">
3668
<ResourcesDropdownButton />
@@ -44,14 +76,77 @@ export function SecondaryNavLinks() {
4476
Docs
4577
</Link>
4678

47-
<Link
48-
className="text-muted-foreground text-sm hover:text-foreground"
49-
href="https://feedback.thirdweb.com"
50-
rel="noopener noreferrer"
51-
target="_blank"
52-
>
53-
Feedback
54-
</Link>
79+
<div className="relative">
80+
<button
81+
type="button"
82+
onClick={() => setShowFeedbackDropdown(!showFeedbackDropdown)}
83+
className="text-muted-foreground text-sm hover:text-foreground border border-border px-3 py-1.5 rounded-full hover:bg-muted transition-colors"
84+
>
85+
Feedback
86+
</button>
87+
88+
{showFeedbackDropdown && (
89+
<div
90+
id="feedback-dropdown"
91+
role="dialog"
92+
aria-labelledby="feedback-heading"
93+
className="absolute top-full right-0 mt-2 bg-background border border-border rounded-2xl p-3 w-96 z-50"
94+
>
95+
<h2
96+
id="feedback-heading"
97+
className="text-foreground text-base font-sans mb-2"
98+
>
99+
Share your feedback with us:
100+
</h2>
101+
<form onSubmit={handleModalSubmit} className="contents">
102+
<label htmlFor="feedback-text" className="sr-only">
103+
Feedback
104+
</label>
105+
<textarea
106+
id="feedback-text"
107+
value={modalFeedback}
108+
onChange={(e) => setModalFeedback(e.target.value)}
109+
maxLength={1000}
110+
aria-describedby="feedback-help"
111+
className="w-full bg-background text-foreground rounded-lg p-4 min-h-[120px] resize-none border border-border focus:border-border focus:outline-none placeholder-muted-foreground font-sans mb-4 text-sm"
112+
placeholder="Tell us what you think..."
113+
/>
114+
115+
<div className="flex items-start justify-between gap-4">
116+
<div className="text-muted-foreground text-xs font-sans">
117+
<div>Have a technical issue?</div>
118+
<div>
119+
<NavLink
120+
href="/team/~/support"
121+
className="underline hover:text-foreground transition-colors"
122+
>
123+
Contact support
124+
</NavLink>
125+
.
126+
</div>
127+
</div>
128+
<div className="flex gap-2 flex-shrink-0">
129+
<button
130+
type="button"
131+
onClick={handleModalCancel}
132+
className="bg-transparent text-foreground px-4 py-1.5 rounded-full font-sans text-sm border border-border hover:bg-muted transition-colors"
133+
>
134+
Cancel
135+
</button>
136+
<button
137+
type="submit"
138+
disabled={!modalFeedback.trim()}
139+
aria-disabled={!modalFeedback.trim()}
140+
className="bg-primary text-primary-foreground px-4 py-1.5 rounded-full font-sans text-sm hover:bg-primary/90 transition-colors disabled:opacity-50"
141+
>
142+
Submit
143+
</button>
144+
</div>
145+
</div>
146+
</form>
147+
</div>
148+
)}
149+
</div>
55150
</div>
56151
);
57152
}

apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"use client";
22

33
import {
4+
ChevronDownIcon,
5+
ChevronUpIcon,
46
LogOutIcon,
57
MenuIcon,
68
MoonIcon,
@@ -12,8 +14,11 @@ import {
1214
import Link from "next/link";
1315
import { useTheme } from "next-themes";
1416
import { useLayoutEffect, useState } from "react";
17+
import { toast } from "sonner";
1518
import type { ThirdwebClient } from "thirdweb";
19+
import { reportProductFeedback } from "@/analytics/report";
1620
import { Button } from "@/components/ui/button";
21+
import { NavLink } from "@/components/ui/NavLink";
1722
import { Separator } from "@/components/ui/separator";
1823
import { SkeletonContainer } from "@/components/ui/skeleton";
1924
import { useEns } from "@/hooks/contract-hooks";
@@ -36,6 +41,8 @@ export function MobileBurgerMenuButton(
3641
},
3742
) {
3843
const [isMenuOpen, setIsMenuOpen] = useState(false);
44+
const [showFeedbackSection, setShowFeedbackSection] = useState(false);
45+
const [modalFeedback, setModalFeedback] = useState("");
3946
const { setTheme, theme } = useTheme();
4047
const ensQuery = useEns({
4148
addressOrEnsName:
@@ -44,6 +51,29 @@ export function MobileBurgerMenuButton(
4451
});
4552
// const [isCMDSearchModalOpen, setIsCMDSearchModalOpen] = useState(false);
4653

54+
const handleModalSubmit = (e?: React.FormEvent) => {
55+
e?.preventDefault();
56+
57+
// Report feedback to PostHog
58+
reportProductFeedback({
59+
feedback: modalFeedback,
60+
source: "mobile",
61+
});
62+
63+
// Show success notification
64+
toast.success("Feedback submitted successfully!", {
65+
description: "Thank you for your feedback. We'll review it shortly.",
66+
});
67+
68+
setModalFeedback("");
69+
setShowFeedbackSection(false);
70+
};
71+
72+
const handleModalCancel = () => {
73+
setModalFeedback("");
74+
setShowFeedbackSection(false);
75+
};
76+
4777
useLayoutEffect(() => {
4878
if (isMenuOpen) {
4979
document.body.style.overflow = "hidden";
@@ -71,7 +101,7 @@ export function MobileBurgerMenuButton(
71101
</Button>
72102

73103
{isMenuOpen && (
74-
<div className="fade-in-0 fixed inset-0 z-50 flex animate-in flex-col bg-background p-6 duration-200">
104+
<div className="fade-in-0 fixed inset-0 z-50 flex animate-in flex-col bg-background p-6 duration-200 overflow-y-auto">
75105
<Button
76106
className="!h-auto absolute top-4 right-4 p-1"
77107
onClick={() => setIsMenuOpen(false)}
@@ -191,14 +221,78 @@ export function MobileBurgerMenuButton(
191221
Docs
192222
</Link>
193223

194-
<Link
195-
className="text-muted-foreground hover:text-foreground"
196-
href="https://feedback.thirdweb.com"
197-
rel="noopener noreferrer"
198-
target="_blank"
199-
>
200-
Feedback
201-
</Link>
224+
<div className="flex flex-col gap-3">
225+
<button
226+
type="button"
227+
className="flex items-center justify-between text-muted-foreground hover:text-foreground"
228+
onClick={() => setShowFeedbackSection(!showFeedbackSection)}
229+
>
230+
<span>Feedback</span>
231+
{showFeedbackSection ? (
232+
<ChevronUpIcon className="size-4" />
233+
) : (
234+
<ChevronDownIcon className="size-4" />
235+
)}
236+
</button>
237+
238+
{showFeedbackSection && (
239+
<div className="pl-0 pr-4 space-y-4 mb-6">
240+
<h3
241+
id="mobile-feedback-heading"
242+
className="text-sm font-medium text-foreground mb-2"
243+
>
244+
Share your feedback with us:
245+
</h3>
246+
<form onSubmit={handleModalSubmit} className="contents">
247+
<label htmlFor="mobile-feedback-text" className="sr-only">
248+
Feedback
249+
</label>
250+
<textarea
251+
id="mobile-feedback-text"
252+
value={modalFeedback}
253+
onChange={(e) => setModalFeedback(e.target.value)}
254+
maxLength={1000}
255+
aria-describedby="mobile-feedback-help"
256+
className="w-full bg-background text-foreground rounded-lg p-3 min-h-[100px] resize-none border border-border focus:border-border focus:outline-none placeholder-muted-foreground font-sans text-sm"
257+
placeholder="Tell us what you think..."
258+
/>
259+
260+
<div className="flex flex-col gap-3">
261+
<p
262+
id="mobile-feedback-help"
263+
className="text-muted-foreground text-xs"
264+
>
265+
Have a technical issue?{" "}
266+
<NavLink
267+
href="/team/~/support"
268+
className="underline hover:text-foreground transition-colors"
269+
>
270+
Contact support
271+
</NavLink>
272+
.
273+
</p>
274+
<div className="flex gap-3">
275+
<button
276+
type="button"
277+
onClick={handleModalCancel}
278+
className="flex-1 bg-transparent text-foreground px-3 py-2 rounded-full font-sans text-sm border border-border hover:bg-muted transition-colors"
279+
>
280+
Cancel
281+
</button>
282+
<button
283+
type="submit"
284+
disabled={!modalFeedback.trim()}
285+
aria-disabled={!modalFeedback.trim()}
286+
className="flex-1 bg-primary text-primary-foreground px-3 py-2 rounded-full font-sans text-sm hover:bg-primary/90 transition-colors disabled:opacity-50"
287+
>
288+
Submit
289+
</button>
290+
</div>
291+
</div>
292+
</form>
293+
</div>
294+
)}
295+
</div>
202296
</div>
203297

204298
<div className="h-6" />

0 commit comments

Comments
 (0)