@@ -4,7 +4,6 @@ import { useSubscription } from "@/hooks/useSubscription";
44import { useRouter } from "next/navigation" ;
55import { useEffect , useState } from "react" ;
66import { useSession } from "next-auth/react" ;
7- import type { Session } from "next-auth" ;
87
98export 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