@@ -15,21 +15,55 @@ const getToken = () => {
1515 return sessionData ?. access_token || "" ;
1616} ;
1717
18+ const getLoginMail = ( ) => {
19+ const storageKey = `sb-${
20+ import . meta. env . VITE_SUPABASE_PROJECT_ID
21+ } -auth-token`;
22+ const sessionDataString = localStorage . getItem ( storageKey ) ;
23+ const sessionData = JSON . parse ( sessionDataString || "null" ) ;
24+ console . log ( "getLoginMail sessionData:" , sessionData ) ;
25+ return sessionData ?. user ?. email || "" ;
26+ } ;
27+
1828const CollaboratePage : React . FC = ( ) => {
1929 const CODESPACE_API_URL = `${ import . meta. env . VITE_BACKEND_URL } /codespaces` ;
2030
2131 const navigate = useNavigate ( ) ;
2232 const { invitationId } = useParams < { invitationId : string } > ( ) ;
2333 const { theme } = useTheme ( ) ;
2434 const { refreshCodespaces } = useCodespaceContext ( ) ;
35+ const [ invitationEmail , setInvitationEmail ] = useState < string | null > ( null ) ;
2536 const [ error , setError ] = useState < string | null > ( null ) ;
2637 const [ isLoading , setIsLoading ] = useState ( false ) ;
2738 const [ showContent , setShowContent ] = useState ( false ) ;
2839
2940 useEffect ( ( ) => {
3041 const timer = setTimeout ( ( ) => setShowContent ( true ) , 100 ) ;
42+
43+ const getInvitationEmail = async ( invitationId : string ) => {
44+ try {
45+ const response = await fetch (
46+ `${ CODESPACE_API_URL } /accept-invitation-email/${ invitationId } ` ,
47+ {
48+ method : "GET" ,
49+ headers : {
50+ "Content-Type" : "application/json" ,
51+ Authorization : getToken ( ) ,
52+ } ,
53+ }
54+ ) ;
55+ setInvitationEmail ( response . ok ? ( await response . json ( ) ) . email : null ) ;
56+ } catch ( error ) {
57+ console . error ( "Error fetching invitation email:" , error ) ;
58+ }
59+ } ;
60+
61+ if ( invitationId ) {
62+ getInvitationEmail ( invitationId ) ;
63+ }
64+
3165 return ( ) => clearTimeout ( timer ) ;
32- } , [ ] ) ;
66+ } , [ CODESPACE_API_URL , invitationId ] ) ;
3367
3468 const handleProceed = async ( ) => {
3569 if ( ! invitationId ) {
@@ -85,6 +119,88 @@ const CollaboratePage: React.FC = () => {
85119 }
86120 } ;
87121
122+ const loginEmail = getLoginMail ( ) ;
123+ const handleLoginRedirect = ( ) => {
124+ localStorage . setItem ( "invitationId" , invitationId || "" ) ;
125+ navigate ( "/login" , { state : { invitationId } } ) ;
126+ } ;
127+
128+ const renderActionButton = ( ) => {
129+ if ( ! loginEmail ) {
130+ return (
131+ < button
132+ onClick = { handleLoginRedirect }
133+ className = { `
134+ w-full px-4 py-2 rounded-md text-sm font-medium
135+ text-white bg-blue-600 hover:bg-blue-700
136+ transition-colors duration-200
137+ flex items-center justify-center gap-2
138+ ` }
139+ >
140+ < ArrowRight className = "w-4 h-4" />
141+ Login with invitation email
142+ </ button >
143+ ) ;
144+ } else if ( loginEmail === invitationEmail ) {
145+ return (
146+ < button
147+ onClick = { handleProceed }
148+ disabled = { isLoading || ! invitationId }
149+ className = { `
150+ w-full px-4 py-2 rounded-md text-sm font-medium
151+ text-white bg-blue-600 hover:bg-blue-700
152+ disabled:opacity-50 disabled:cursor-not-allowed
153+ transition-colors duration-200
154+ flex items-center justify-center gap-2
155+ ${ isLoading ? "cursor-wait" : "" }
156+ ` }
157+ >
158+ { isLoading ? (
159+ < >
160+ < div className = "w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" > </ div >
161+ Processing...
162+ </ >
163+ ) : (
164+ < >
165+ < ArrowRight className = "w-4 h-4" />
166+ Proceed
167+ </ >
168+ ) }
169+ </ button >
170+ ) ;
171+ } else {
172+ return (
173+ < div className = "space-y-3" >
174+ < div
175+ className = { `p-3 ${ theme . surface } border border-yellow-500 rounded-md mb-3` }
176+ >
177+ < div className = "flex items-center gap-2" >
178+ < AlertCircle className = "w-4 h-4 text-yellow-500 flex-shrink-0" />
179+ < p className = { `text-sm ${ theme . text } ` } >
180+ You're logged in as{ " " }
181+ < span className = "font-semibold" > { loginEmail } </ span > , but this
182+ invitation is for{ " " }
183+ < span className = "font-semibold" > { invitationEmail } </ span >
184+ </ p >
185+ </ div >
186+ </ div >
187+ < button
188+ onClick = { handleLoginRedirect }
189+ className = { `
190+ w-full px-4 py-2 rounded-md text-sm font-medium
191+ text-white bg-blue-600 hover:bg-blue-700
192+ transition-colors duration-200
193+ flex items-center justify-center gap-2
194+ ` }
195+ >
196+ < ArrowRight className = "w-4 h-4" />
197+ Login with invitation email
198+ </ button >
199+ </ div >
200+ ) ;
201+ }
202+ } ;
203+
88204 return (
89205 < div
90206 className = { `min-h-screen flex items-center justify-center p-4 ${ theme . surface } ` }
@@ -139,6 +255,23 @@ const CollaboratePage: React.FC = () => {
139255 button below to join the workspace and start coding together.
140256 </ p >
141257
258+ { invitationEmail && (
259+ < div
260+ className = { `p-3 ${ theme . surface } border ${ theme . border } rounded-md mb-3` }
261+ >
262+ < p
263+ className = { `text-xs ${ theme . textSecondary } mb-2 uppercase tracking-wide` }
264+ >
265+ Invitation Email
266+ </ p >
267+ < code
268+ className = { `text-sm font-mono ${ theme . text } block break-all` }
269+ >
270+ { invitationEmail }
271+ </ code >
272+ </ div >
273+ ) }
274+
142275 { invitationId && (
143276 < div
144277 className = { `p-3 ${ theme . surface } border ${ theme . border } rounded-md` }
@@ -158,32 +291,7 @@ const CollaboratePage: React.FC = () => {
158291 </ div >
159292
160293 { /* Action Buttons */ }
161- < div className = "space-y-3" >
162- < button
163- onClick = { handleProceed }
164- disabled = { isLoading || ! invitationId }
165- className = { `
166- w-full px-4 py-2 rounded-md text-sm font-medium
167- text-white bg-blue-600 hover:bg-blue-700
168- disabled:opacity-50 disabled:cursor-not-allowed
169- transition-colors duration-200
170- flex items-center justify-center gap-2
171- ${ isLoading ? "cursor-wait" : "" }
172- ` }
173- >
174- { isLoading ? (
175- < >
176- < div className = "w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" > </ div >
177- Processing...
178- </ >
179- ) : (
180- < >
181- < ArrowRight className = "w-4 h-4" />
182- Accept Invitation
183- </ >
184- ) }
185- </ button >
186- </ div >
294+ < div className = "space-y-3" > { renderActionButton ( ) } </ div >
187295
188296 { /* Status indicator */ }
189297 < div className = { `mt-4 pt-4 border-t ${ theme . border } ` } >
0 commit comments