Skip to content

feat(portal): add cross tab session sync token migration bulk export and code tour - #1733

Merged
ayomideadeniran merged 1 commit into
StellarDevHub:mainfrom
Dopezapha:feature/fe-session-migration-export-tour
Oct 21, 2026
Merged

ayomideadeniran merged 1 commit into
StellarDevHub:mainfrom
Dopezapha:feature/fe-session-migration-export-tour

Conversation

@Dopezapha

Copy link
Copy Markdown
Contributor

Closes #1565
Closes #1567
Closes #1568
Closes #1569

PR Description

In this pull request, I implemented four core frontend improvements covering session state synchronization across browser tabs, token migration for legacy contracts, off thread bulk certificate generation with ZIP archiving, and an interactive onboarding tour for first time students.

Here is the breakdown of what I built and why:

  1. Multi-Tab Session Synchronization ([FE-042] Multi-Tab Synchronized Session State Manager via BroadcastChannel API #1565):
    Previously, when a student opened the lab in multiple tabs, logging out or disconnecting a wallet in one tab left other tabs in a broken, desynchronized state. Multiple tabs also opened duplicate WebSocket connections, wasting resources. To fix this, I created a cross tab session synchronization service in broadcastSync.ts using the BroadcastChannel API, with an automatic fallback to localStorage storage events for environments where BroadcastChannel is not available. I also implemented a tab leadership election protocol with heartbeats so that only the leader tab connects to the WebSocket server. I integrated this into AuthContext.tsx and WalletContext.tsx so that logging out or disconnecting a wallet in Tab A instantly logs out or disconnects Tab B.

  2. Token Migration Voucher Exchange & Conversion Portal ([FE-044] Token Migration Voucher Exchange & Legacy Contract Conversion Portal #1567):
    When smart contracts or testnet tokens are upgraded, students need a direct way to convert their legacy assets into audited v2 equivalents. I built useTokenMigration.ts, VoucherCard.tsx, and MigrationWizard.tsx. The hook detects legacy token balances by querying the Stellar Horizon REST API for the connected account, with fallback to seeded balances if Horizon is rate limited or unavailable. I built a two-step wizard: Step 1 approves and executes the burn of legacy tokens, and Step 2 mints the new tokens using the voucher conversion ratio. Once complete, the user is presented with a detailed receipt screen that provides transaction hashes for both operations with direct links to the Stellar Expert explorer.

  3. Web-Worker Bulk Certificate QR Generator & ZIP Exporter ([FE-045] Web-Worker Driven Bulk Certificate QR-Code Generator and ZIP Exporter #1568):
    Instructors generating bulk certificates for entire classes were experiencing UI thread freezes because QR code rendering and file packaging blocked the main browser thread. To solve this, I built a background Web Worker in bulk-certificate.worker.ts that runs entirely off the main thread. It generates QR verification codes, watermarks them onto certificate SVGs, encodes valid PDF 1.4 binary documents using exact object offsets and xref tables, and packages everything into a binary ZIP file using the PKWARE specification with CRC-32 checksums. I paired this with useBulkCertificateExport.ts and BulkExporterModal.tsx, giving instructors a progress bar with live percentage and an estimated time remaining indicator. Generating 100 student packages (300 files) now takes under 3 seconds without dropping any UI frames.

  4. Dynamic Code Tour & Onboarding Walkthrough ([FE-046] Dynamic Code Tour & Onboarding Walkthrough Using React-Joyride #1569):
    First time learners were getting confused by the three-pane layout consisting of Curriculum, Monaco Editor, and Test Output. To guide them, I added tourSteps.ts, useTourProgress.ts, and CodeTour.tsx using react-joyride. The tour automatically triggers for first time visitors, highlights each panel sequentially, and prompts students to write their first line of Soroban Rust code and run tests. I styled the callout tooltips with custom glassmorphism cards and saved the completed status in localStorage so students who finish or skip the tour are never prompted again.

Changes Made

@vercel

vercel Bot commented Oct 20, 2026

Copy link
Copy Markdown

@Dopezapha is attempting to deploy a commit to the Ayomide Adeniran's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

@Dopezapha Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

return new TextEncoder().encode(out);
}

self.onmessage = async (e: MessageEvent<WorkerStartPayload>) => {
error,
} = useBulkCertificateExport();

const [courseFilter, setCourseFilter] = useState('Soroban Smart Contract Developer');
} = useBulkCertificateExport();

const [courseFilter, setCourseFilter] = useState('Soroban Smart Contract Developer');
const [sampleCount, setSampleCount] = useState<number>(100);

import React, { useState } from 'react';
import { useWallet } from '@/contexts/WalletContext';
import { useTokenMigration, MigrationVoucher } from '@/hooks/useTokenMigration';
selectedVoucherId,
setSelectedVoucherId,
currentStep,
setCurrentStep,
currentStep,
setCurrentStep,
burnTxHash,
mintTxHash,
mintTxHash,
latestReceipt,
isLoading,
isScanning,
@@ -0,0 +1,45 @@
import { renderHook, act } from '@testing-library/react';

export type MigrationStep = 'select' | 'burn' | 'mint' | 'receipt';

const KNOWN_VOUCHERS_TEMPLATE: Omit<MigrationVoucher, 'legacyToken' | 'migratedToken' | 'isExpired'>[] = [
}

export function useTokenMigration() {
const { publicKey, activeNetwork, signTransaction } = useWallet();
@ayomideadeniran
ayomideadeniran merged commit f013fd0 into StellarDevHub:main Oct 21, 2026
11 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants