@@ -5,19 +5,14 @@ import {
55 PlayerStatsTree ,
66 UserMeResponse ,
77} from "../core/ApiSchemas" ;
8+ import { fetchPlayerById , getUserMe } from "./Api" ;
9+ import { discordLogin , logOut , sendMagicLink } from "./Auth" ;
810import "./components/baseComponents/stats/DiscordUserHeader" ;
911import "./components/baseComponents/stats/GameList" ;
1012import "./components/baseComponents/stats/PlayerStatsTable" ;
1113import "./components/baseComponents/stats/PlayerStatsTree" ;
1214import "./components/Difficulties" ;
1315import "./components/PatternButton" ;
14- import {
15- discordLogin ,
16- fetchPlayerById ,
17- getApiBase ,
18- getUserMe ,
19- logOut ,
20- } from "./jwt" ;
2116import { isInIframe , translateText } from "./Utils" ;
2217
2318@customElement ( "account-modal" )
@@ -30,10 +25,7 @@ export class AccountModal extends LitElement {
3025 @state ( ) private email : string = "" ;
3126 @state ( ) private isLoadingUser : boolean = false ;
3227
33- private loggedInEmail : string | null = null ;
34- private loggedInDiscord : string | null = null ;
3528 private userMeResponse : UserMeResponse | null = null ;
36- private playerId : string | null = null ;
3729 private statsTree : PlayerStatsTree | null = null ;
3830 private recentGames : PlayerGame [ ] = [ ] ;
3931
@@ -44,8 +36,7 @@ export class AccountModal extends LitElement {
4436 const customEvent = event as CustomEvent ;
4537 if ( customEvent . detail ) {
4638 this . userMeResponse = customEvent . detail as UserMeResponse ;
47- this . playerId = this . userMeResponse ?. player ?. publicId ;
48- if ( this . playerId === undefined ) {
39+ if ( this . userMeResponse ?. player ?. publicId === undefined ) {
4940 this . statsTree = null ;
5041 this . recentGames = [ ] ;
5142 }
@@ -67,82 +58,90 @@ export class AccountModal extends LitElement {
6758 id ="account-modal "
6859 title ="${ translateText ( "account_modal.title" ) || "Account" } "
6960 >
70- ${ this . renderInner ( ) }
61+ ${ this . isLoadingUser
62+ ? html `
63+ < div
64+ class ="flex flex-col items-center justify-center p-6 text-white "
65+ >
66+ < p class ="mb-2 ">
67+ ${ translateText ( "account_modal.fetching_account" ) }
68+ </ p >
69+ < div
70+ class ="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin "
71+ > </ div >
72+ </ div >
73+ `
74+ : this . renderInner ( ) }
7175 </ o-modal >
7276 ` ;
7377 }
7478
7579 private renderInner ( ) {
76- if ( this . isLoadingUser ) {
77- return html `
78- < div class ="flex flex-col items-center justify-center p-6 text-white ">
79- < p class ="mb-2 "> ${ translateText ( "account_modal.fetching_account" ) } </ p >
80- < div
81- class ="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin "
82- > </ div >
83- </ div >
84- ` ;
85- }
86- if ( this . loggedInDiscord ) {
87- return this . renderLoggedInDiscord ( ) ;
88- } else if ( this . loggedInEmail ) {
89- return this . renderLoggedInEmail ( ) ;
80+ if ( this . userMeResponse ?. user ) {
81+ return this . renderAccountInfo ( ) ;
9082 } else {
9183 return this . renderLoginOptions ( ) ;
9284 }
9385 }
9486
95- private viewGame ( gameId : string ) : void {
96- this . close ( ) ;
97- const path = location . pathname ;
98- const { search } = location ;
99- const hash = `#join=${ encodeURIComponent ( gameId ) } ` ;
100- const newUrl = `${ path } ${ search } ${ hash } ` ;
101-
102- history . pushState ( { join : gameId } , "" , newUrl ) ;
103- window . dispatchEvent ( new HashChangeEvent ( "hashchange" ) ) ;
104- }
105-
106- private renderLoggedInDiscord ( ) {
87+ private renderAccountInfo ( ) {
10788 return html `
10889 < div class ="p-6 ">
109- < div class ="mb-4 text-center ">
110- < p class ="text-white mb-4 ">
111- Logged in with Discord as ${ this . loggedInDiscord }
90+ < div class ="mb-4 ">
91+ < p class ="text-white mb-4 text-center ">
92+ Player ID: ${ this . userMeResponse ?. player ?. publicId }
11293 </ p >
113- ${ this . logoutButton ( ) }
94+ </ div >
95+ < div class ="mb-4 text-center ">
96+ < p class ="text-white mb-4 "> ${ this . renderLoggedInAs ( ) } </ p >
11497 </ div >
11598 < div class ="flex flex-col items-center mt-2 mb-4 ">
11699 < discord-user-header
117100 .data =${ this . userMeResponse ?. user ?. discord ?? null }
118101 > </ discord-user-header >
119- < player-stats-tree-view
120- .statsTree =${ this . statsTree }
121- > </ player-stats-tree-view >
122- < hr class ="w-2/3 border-gray-600 my-2 " />
123- < game-list
124- .games =${ this . recentGames }
125- .onViewGame =${ ( id : string ) => this . viewGame ( id ) }
126- > </ game-list >
127102 </ div >
103+ ${ this . renderPlayerStats ( ) }
128104 </ div >
129105 ` ;
130106 }
131107
132- private renderLoggedInEmail ( ) : TemplateResult {
108+ private renderLoggedInAs ( ) : TemplateResult {
109+ const me = this . userMeResponse ?. user ;
110+ if ( me ?. discord ) {
111+ return html `< p > Logged in as ${ me . discord . global_name } </ p >
112+ ${ this . renderLogoutButton ( ) } ` ;
113+ } else if ( me ?. email ) {
114+ return html `< p > Logged in as ${ me . email } </ p >
115+ ${ this . renderLogoutButton ( ) } ` ;
116+ }
117+ return this . renderLoginOptions ( ) ;
118+ }
119+
120+ private renderPlayerStats ( ) : TemplateResult {
133121 return html `
134- < div class =" p-6 " >
135- < div class =" mb-4 " >
136- < p class =" text-white text-center mb-4 " >
137- Logged in as ${ this . loggedInEmail }
138- </ p >
139- </ div >
140- ${ this . logoutButton ( ) }
141- </ div >
122+ < player-stats-tree-view
123+ .statsTree = ${ this . statsTree }
124+ > </ player-stats-tree-view >
125+ < hr class =" w-2/3 border-gray-600 my-2 " />
126+ < game-list
127+ .games = ${ this . recentGames }
128+ .onViewGame = ${ ( id : string ) => this . viewGame ( id ) }
129+ > </ game-list >
142130 ` ;
143131 }
144132
145- private logoutButton ( ) : TemplateResult {
133+ private viewGame ( gameId : string ) : void {
134+ this . close ( ) ;
135+ const path = location . pathname ;
136+ const { search } = location ;
137+ const hash = `#join=${ encodeURIComponent ( gameId ) } ` ;
138+ const newUrl = `${ path } ${ search } ${ hash } ` ;
139+
140+ history . pushState ( { join : gameId } , "" , newUrl ) ;
141+ window . dispatchEvent ( new HashChangeEvent ( "hashchange" ) ) ;
142+ }
143+
144+ private renderLogoutButton ( ) : TemplateResult {
146145 return html `
147146 < button
148147 @click ="${ this . handleLogout } "
@@ -157,10 +156,6 @@ export class AccountModal extends LitElement {
157156 return html `
158157 < div class ="p-6 ">
159158 < div class ="mb-6 ">
160- < h3 class ="text-lg font-medium text-white mb-4 text-center ">
161- Choose your login method
162- </ h3 >
163-
164159 <!-- Discord Login Button -->
165160 < div class ="mb-6 ">
166161 < button
@@ -195,7 +190,6 @@ export class AccountModal extends LitElement {
195190 for ="email "
196191 class ="block text-sm font-medium text-white mb-2 "
197192 >
198- Recover account by email
199193 </ label >
200194 < input
201195 type ="email "
@@ -225,6 +219,12 @@ export class AccountModal extends LitElement {
225219 </ button >
226220 </ div >
227221 </ div >
222+ < button
223+ @click ="${ this . handleLogout } "
224+ class ="px-3 py-1 text-xs font-medium text-white bg-red-600 border border-transparent rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-colors duration-200 "
225+ >
226+ Clear
227+ </ button >
228228 ` ;
229229 }
230230
@@ -239,37 +239,15 @@ export class AccountModal extends LitElement {
239239 return ;
240240 }
241241
242- try {
243- const apiBase = getApiBase ( ) ;
244- const response = await fetch ( `${ apiBase } /magic-link` , {
245- method : "POST" ,
246- headers : {
247- "Content-Type" : "application/json" ,
248- } ,
249- body : JSON . stringify ( {
250- redirectDomain : window . location . origin ,
242+ const success = await sendMagicLink ( this . email ) ;
243+ if ( success ) {
244+ alert (
245+ translateText ( "account_modal.recovery_email_sent" , {
251246 email : this . email ,
252247 } ) ,
253- } ) ;
254-
255- if ( response . ok ) {
256- alert (
257- translateText ( "account_modal.recovery_email_sent" , {
258- email : this . email ,
259- } ) ,
260- ) ;
261- this . close ( ) ;
262- } else {
263- console . error (
264- "Failed to send recovery email:" ,
265- response . status ,
266- response . statusText ,
267- ) ;
268- alert ( "Failed to send recovery email. Please try again." ) ;
269- }
270- } catch ( error ) {
271- console . error ( "Error sending recovery email:" , error ) ;
272- alert ( "Error sending recovery email. Please try again." ) ;
248+ ) ;
249+ } else {
250+ alert ( "Failed to send recovery email" ) ;
273251 }
274252 }
275253
@@ -284,14 +262,10 @@ export class AccountModal extends LitElement {
284262 void getUserMe ( )
285263 . then ( ( userMe ) => {
286264 if ( userMe ) {
287- this . loggedInEmail = userMe . user . email ?? null ;
288- this . loggedInDiscord = userMe . user . discord ?. global_name ?? null ;
289- if ( this . playerId ) {
290- this . loadFromApi ( this . playerId ) ;
265+ this . userMeResponse = userMe ;
266+ if ( this . userMeResponse ?. player ?. publicId ) {
267+ this . loadPlayerProfile ( this . userMeResponse . player . publicId ) ;
291268 }
292- } else {
293- this . loggedInEmail = null ;
294- this . loggedInDiscord = null ;
295269 }
296270 this . isLoadingUser = false ;
297271 this . requestUpdate ( ) ;
@@ -315,9 +289,9 @@ export class AccountModal extends LitElement {
315289 window . location . reload ( ) ;
316290 }
317291
318- private async loadFromApi ( playerId : string ) : Promise < void > {
292+ private async loadPlayerProfile ( publicId : string ) : Promise < void > {
319293 try {
320- const data = await fetchPlayerById ( playerId ) ;
294+ const data = await fetchPlayerById ( publicId ) ;
321295 if ( ! data ) {
322296 this . requestUpdate ( ) ;
323297 return ;
0 commit comments