diff --git a/apps/web/src/app/features/onboard/onboard.component.html b/apps/web/src/app/features/onboard/onboard.component.html index 6e42228..5c9129c 100644 --- a/apps/web/src/app/features/onboard/onboard.component.html +++ b/apps/web/src/app/features/onboard/onboard.component.html @@ -63,6 +63,20 @@

+ @if(initError()){ +

Something went wrong

+

+ We couldn't load your account. This can happen due to a temporary + connection issue. +

+ + } @else { @if(step() === STEPS.PERSON){ Your account has been updated

> Finish Setup - } + } } diff --git a/apps/web/src/app/features/onboard/onboard.component.ts b/apps/web/src/app/features/onboard/onboard.component.ts index 79e1440..c616c76 100644 --- a/apps/web/src/app/features/onboard/onboard.component.ts +++ b/apps/web/src/app/features/onboard/onboard.component.ts @@ -80,6 +80,7 @@ export class OnboardComponent implements OnInit { loading: WritableSignal = signal(true); nextLoading: WritableSignal = signal(false); apiError: WritableSignal = signal(''); + initError: WritableSignal = signal(false); showPersonErrors: WritableSignal = signal(false); showWalletErrors: WritableSignal = signal(false); @@ -96,6 +97,10 @@ export class OnboardComponent implements OnInit { editWalletLoading: WritableSignal = signal(false); editWalletShowErrors: WritableSignal = signal(false); + private tokenExchanged = false; + private initRetries = 0; + private readonly MAX_INIT_RETRIES = 3; + async ngOnInit(): Promise { this.meta.SetMeta(this.seo); try { @@ -106,9 +111,10 @@ export class OnboardComponent implements OnInit { // Load platform config for branding (pass token for correct platform context) await this.configService.LoadConfig(token || undefined); - // Exchange token for session if present - if (token) { + // Exchange token for session if present (only on first load, not retries) + if (token && !this.tokenExchanged) { await this.accountLinkService.ExchangeToken(token); + this.tokenExchanged = true; } const account = await this.accountService.GetAccount(); @@ -118,19 +124,38 @@ export class OnboardComponent implements OnInit { if (account) { await this.externalWalletService.GetExternalWallets(account.id); } + + // Check: may fail loading data due to network error after token exchange, allows for retries. + if (!this.accountService.account() || !this.personService.person()) { + this.initError.set(true); + this.loading.set(false); + return; + } + this.DetermineInitialStep(); this.loading.set(false); } catch (error) { console.error(error); - // Redirect to session expired page on any auth error if (this.accountLinkService.linkError()) { this.router.navigateByUrl('/session-expired?reason=link_expired'); return; } + this.initError.set(true); this.loading.set(false); } } + async RetryInit(): Promise { + this.initRetries++; + if (this.initRetries >= this.MAX_INIT_RETRIES) { + this.router.navigateByUrl('/session-expired?reason=load_failed'); + return; + } + this.initError.set(false); + this.loading.set(true); + await this.ngOnInit(); + } + CheckUrlParams(): void { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString);