Skip to content

Commit 6395344

Browse files
committed
feat: basic client side error handling
1 parent 4d27e3e commit 6395344

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from "../../../../(main)/websites/[id]/users/[userId]/page";
2+

apps/docs/components/feedback.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type Feedback = {
3131

3232
export type ActionResponse = {
3333
success: boolean;
34+
error?: string;
3435
};
3536

3637
interface Result extends Feedback {
@@ -46,6 +47,7 @@ export function Feedback({
4647
const [previous, setPrevious] = useState<Result | null>(null);
4748
const [opinion, setOpinion] = useState<"good" | "bad" | null>(null);
4849
const [message, setMessage] = useState("");
50+
const [error, setError] = useState<string | null>(null);
4951
const [isPending, startTransition] = useTransition();
5052

5153
useEffect(() => {
@@ -72,19 +74,25 @@ export function Feedback({
7274
return;
7375
}
7476

77+
setError(null);
78+
7579
startTransition(() => {
7680
const feedback: Feedback = {
7781
opinion,
7882
message,
7983
};
8084

8185
onRateAction(url, feedback).then((response) => {
82-
setPrevious({
83-
response,
84-
...feedback,
85-
});
86-
setMessage("");
87-
setOpinion(null);
86+
if (response.success) {
87+
setPrevious({
88+
response,
89+
...feedback,
90+
});
91+
setMessage("");
92+
setOpinion(null);
93+
} else {
94+
setError(response.error ?? "Something went wrong");
95+
}
8896
});
8997
});
9098

@@ -154,6 +162,7 @@ export function Feedback({
154162
onClick={() => {
155163
setOpinion(previous.opinion);
156164
setPrevious(null);
165+
setError(null);
157166
}}
158167
type="button"
159168
>
@@ -164,8 +173,18 @@ export function Feedback({
164173
<form className="flex flex-col gap-3" onSubmit={submit}>
165174
<textarea
166175
autoFocus
167-
className="resize-none rounded border border-border bg-muted/30 p-3 text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50"
168-
onChange={(e) => setMessage(e.target.value)}
176+
className={cn(
177+
"resize-none rounded border bg-muted/30 p-3 text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1",
178+
error
179+
? "border-red-500 focus-visible:ring-red-500/50"
180+
: "border-border focus-visible:ring-primary/50"
181+
)}
182+
onChange={(e) => {
183+
setMessage(e.target.value);
184+
if (error) {
185+
setError(null);
186+
}
187+
}}
169188
onKeyDown={(e) => {
170189
if (!e.shiftKey && e.key === "Enter") {
171190
submit(e);
@@ -175,6 +194,7 @@ export function Feedback({
175194
required
176195
value={message}
177196
/>
197+
{error && <p className="text-red-500 text-sm">{error}</p>}
178198
<button
179199
className={cn(
180200
buttonVariants({ variant: "outline" }),

apps/docs/lib/feedback-action.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,39 @@ const client = new Databuddy({
88
debug: process.env.NODE_ENV === "development",
99
});
1010

11+
const MAX_MESSAGE_LENGTH = 1000;
12+
const VALID_OPINIONS = ["good", "bad"] as const;
13+
1114
export async function onRateDocs(
1215
url: string,
1316
feedback: Feedback
1417
): Promise<ActionResponse> {
18+
19+
if (!VALID_OPINIONS.includes(feedback.opinion)) {
20+
return { success: false, error: "Please select good or bad" };
21+
}
22+
23+
if (typeof feedback.message !== "string") {
24+
return { success: false, error: "Message is required" };
25+
}
26+
27+
const trimmedMessage = feedback.message.trim();
28+
29+
if (trimmedMessage.length === 0) {
30+
return { success: false, error: "Message cannot be empty" };
31+
}
32+
33+
if (trimmedMessage.length > MAX_MESSAGE_LENGTH) {
34+
return { success: false, error: `Message must be under ${MAX_MESSAGE_LENGTH} characters` };
35+
}
36+
1537
try {
1638
await client.track({
1739
name: "docs_feedback",
1840
properties: {
1941
url,
2042
opinion: feedback.opinion,
21-
message: feedback.message,
43+
message: trimmedMessage,
2244
},
2345
});
2446

@@ -27,7 +49,7 @@ export async function onRateDocs(
2749
return { success: true };
2850
} catch (error) {
2951
console.error("Failed to capture docs feedback:", error);
30-
return { success: false };
52+
return { success: false, error: "Something went wrong. Please try again." };
3153
}
3254
}
3355

0 commit comments

Comments
 (0)