Skip to content

Commit 79f0d6c

Browse files
authored
Merge pull request #222 from apsinghdev/feat/dash-cum
[chore] add join community btn in pro/dash
2 parents 1b1eaff + 82d19dc commit 79f0d6c

File tree

1 file changed

+88
-1
lines changed
  • apps/web/src/app/(main)/dashboard/pro/dashboard

1 file changed

+88
-1
lines changed

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

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,93 @@
22

33
import { useSubscription } from "@/hooks/useSubscription";
44
import { useRouter } from "next/navigation";
5-
import { useEffect } from "react";
5+
import { useEffect, useState } from "react";
6+
import { useSession } from "next-auth/react";
67

78
export default function ProDashboardPage() {
89
const { isPaidUser, isLoading } = useSubscription();
910
const router = useRouter();
11+
const { data: session } = useSession();
12+
const [error, setError] = useState<string | null>(null);
13+
const [isJoining, setIsJoining] = useState(false);
1014

1115
useEffect(() => {
1216
if (!isLoading && !isPaidUser) {
1317
router.push("/pricing");
1418
}
1519
}, [isPaidUser, isLoading, router]);
1620

21+
const handleJoinSlack: () => Promise<void> = async () => {
22+
if (isJoining) return;
23+
24+
setIsJoining(true);
25+
setError(null);
26+
27+
try {
28+
if (!session?.user) {
29+
setError("Please sign in to join the community");
30+
return;
31+
}
32+
33+
const accessToken = session?.accessToken;
34+
35+
if (!accessToken || typeof accessToken !== "string") {
36+
setError("Authentication token not found");
37+
return;
38+
}
39+
40+
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:4000";
41+
const response = await fetch(`${apiUrl}/join-community`, {
42+
method: "GET",
43+
headers: {
44+
Authorization: `Bearer ${accessToken}`,
45+
},
46+
});
47+
48+
if (!response.ok) {
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");
80+
return;
81+
}
82+
83+
window.location.href = slackInviteUrl;
84+
} catch (err) {
85+
console.error("Failed to join community:", err);
86+
setError("Failed to connect to server");
87+
} finally {
88+
setIsJoining(false);
89+
}
90+
};
91+
1792
if (isLoading) {
1893
return (
1994
<div className="w-full h-full flex items-center justify-center bg-ox-content">
@@ -33,6 +108,18 @@ export default function ProDashboardPage() {
33108
hi investors, ajeetunc is on the way to deliver the shareholder value.
34109
soon you&apos;ll see all the pro perks here. thanks for investing
35110
</h1>
111+
{isPaidUser && (
112+
<div className="mt-6">
113+
<button
114+
onClick={handleJoinSlack}
115+
disabled={isJoining}
116+
className="px-4 py-2 bg-brand-purple hover:bg-brand-purple-light text-text-primary font-medium rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed text-sm"
117+
>
118+
{isJoining ? "Joining..." : "Join Slack"}
119+
</button>
120+
{error && <p className="text-error-text text-sm mt-2">{error}</p>}
121+
</div>
122+
)}
36123
</div>
37124
</div>
38125
);

0 commit comments

Comments
 (0)