Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion apps/web/src/app/features/onboard/onboard.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ <h1 class="partner-heading">
<!-- Right Panel - Form Content -->
<div class="right-panel">
<div class="right-panel-content">
@if(initError()){
<h1>Something went wrong</h1>
<p>
We couldn't load your account. This can happen due to a temporary
connection issue.
</p>
<button
type="button"
class="action-button action-button-wide"
(click)="RetryInit()"
>
Try again
</button>
} @else {
<!-- Step 1: Person Details -->
@if(step() === STEPS.PERSON){
<app-person-form
Expand Down Expand Up @@ -230,7 +244,7 @@ <h1>Your account has been updated</h1>
>
Finish Setup
</button>
}
} }
</div>
</div>
</div>
Expand Down
31 changes: 28 additions & 3 deletions apps/web/src/app/features/onboard/onboard.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export class OnboardComponent implements OnInit {
loading: WritableSignal<boolean> = signal(true);
nextLoading: WritableSignal<boolean> = signal(false);
apiError: WritableSignal<string> = signal('');
initError: WritableSignal<boolean> = signal(false);

showPersonErrors: WritableSignal<boolean> = signal(false);
showWalletErrors: WritableSignal<boolean> = signal(false);
Expand All @@ -96,6 +97,10 @@ export class OnboardComponent implements OnInit {
editWalletLoading: WritableSignal<boolean> = signal(false);
editWalletShowErrors: WritableSignal<boolean> = signal(false);

private tokenExchanged = false;
private initRetries = 0;
private readonly MAX_INIT_RETRIES = 3;

async ngOnInit(): Promise<void> {
this.meta.SetMeta(this.seo);
try {
Expand All @@ -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();
Expand All @@ -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<void> {
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);
Expand Down
Loading