Skip to content

Commit 82d19dc

Browse files
committed
refactor: type the handler and harden success/error handling
1 parent 405db08 commit 82d19dc

1 file changed

Lines changed: 45 additions & 21 deletions

File tree

  • apps/web/src/app/(main)/dashboard/pro/dashboard

apps/web/src/app/(main)/dashboard/pro/dashboard/page.tsx

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useSubscription } from "@/hooks/useSubscription";
44
import { useRouter } from "next/navigation";
55
import { useEffect, useState } from "react";
66
import { useSession } from "next-auth/react";
7-
import type { Session } from "next-auth";
87

98
export default function ProDashboardPage() {
109
const { isPaidUser, isLoading } = useSubscription();
@@ -19,26 +18,25 @@ export default function ProDashboardPage() {
1918
}
2019
}, [isPaidUser, isLoading, router]);
2120

22-
const handleJoinSlack = async () => {
21+
const handleJoinSlack: () => Promise<void> = async () => {
2322
if (isJoining) return;
23+
2424
setIsJoining(true);
2525
setError(null);
2626

27-
if (!session?.user) {
28-
setError("Please sign in to join the community");
29-
setIsJoining(false);
30-
return;
31-
}
27+
try {
28+
if (!session?.user) {
29+
setError("Please sign in to join the community");
30+
return;
31+
}
3232

33-
const accessToken = (session as Session)?.accessToken;
33+
const accessToken = session?.accessToken;
3434

35-
if (!accessToken) {
36-
setError("Authentication token not found");
37-
setIsJoining(false);
38-
return;
39-
}
35+
if (!accessToken || typeof accessToken !== "string") {
36+
setError("Authentication token not found");
37+
return;
38+
}
4039

41-
try {
4240
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:4000";
4341
const response = await fetch(`${apiUrl}/join-community`, {
4442
method: "GET",
@@ -48,17 +46,45 @@ export default function ProDashboardPage() {
4846
});
4947

5048
if (!response.ok) {
51-
const errorData = await response.json();
52-
setError(errorData.error || "Failed to join community");
53-
setIsJoining(false);
49+
let errorMessage = "Failed to join community";
50+
try {
51+
const errorData = await response.json();
52+
errorMessage = errorData.error || errorMessage;
53+
} catch {
54+
// if json parsing fails, use default message
55+
}
56+
setError(errorMessage);
57+
return;
58+
}
59+
60+
let responseData: { slackInviteUrl?: string };
61+
try {
62+
responseData = await response.json();
63+
} catch {
64+
setError("Invalid response from server");
65+
return;
66+
}
67+
68+
const { slackInviteUrl } = responseData;
69+
70+
if (!slackInviteUrl || typeof slackInviteUrl !== "string") {
71+
setError("Invalid Slack invite URL received");
72+
return;
73+
}
74+
75+
// validate url format
76+
try {
77+
new URL(slackInviteUrl);
78+
} catch {
79+
setError("Invalid Slack invite URL format");
5480
return;
5581
}
5682

57-
const { slackInviteUrl } = await response.json();
5883
window.location.href = slackInviteUrl;
5984
} catch (err) {
6085
console.error("Failed to join community:", err);
6186
setError("Failed to connect to server");
87+
} finally {
6288
setIsJoining(false);
6389
}
6490
};
@@ -91,9 +117,7 @@ export default function ProDashboardPage() {
91117
>
92118
{isJoining ? "Joining..." : "Join Slack"}
93119
</button>
94-
{error && (
95-
<p className="text-error-text text-sm mt-2">{error}</p>
96-
)}
120+
{error && <p className="text-error-text text-sm mt-2">{error}</p>}
97121
</div>
98122
)}
99123
</div>

0 commit comments

Comments
 (0)