Wire the module completion flow to mint Badge NFTs on Stellar Testnet when users pass quizzes.
I've created the updated versions of the files with the suffix _NEW.tsx:
- QuizView_NEW.tsx - Updated quiz component with blockchain integration
- EarnedNfts_NEW.tsx - Updated achievements page with on-chain verification
# Backup the original
copy "src\app\dashboard\ruta_aprendizaje\components\QuizView.tsx" "src\app\dashboard\ruta_aprendizaje\components\QuizView.tsx.backup"
# Replace with new version
copy "QuizView_NEW.tsx" "src\app\dashboard\ruta_aprendizaje\components\QuizView.tsx"
# Delete the temp file
del "QuizView_NEW.tsx"# Backup the original
copy "src\app\dashboard\logros\EarnedNfts.tsx" "src\app\dashboard\logros\EarnedNfts.tsx.backup"
# Replace with new version
copy "EarnedNfts_NEW.tsx" "src\app\dashboard\logros\EarnedNfts.tsx"
# Delete the temp file
del "EarnedNfts_NEW.tsx"-
Added Imports:
useStellarWallet- Get connected wallet addressuseStellarProgress- Check badge status and refresh on-chain datarewardQuiz,mintBadge- API client functionstoast- User notifications
-
Added State:
submitting- Track blockchain submission progressbadgeMinted- Track if badge was successfully minted
-
New Function:
submitToBlockchain()- Checks if badge already exists with
checkHasBadge(module.id) - Calls
rewardQuizAPI with challengeId =${module.id}-quiz - If passed (score >= 75), calls
mintBadgewith:moduleId: Exact module.id from courses.tsmoduleTitle: module.titlexpEarned: Actual XP from reward_quiz resultquizScore: Final quiz score (0-100)
- Refreshes on-chain progress
- Shows success/error toasts
- Checks if badge already exists with
-
Updated
handleNext():- Calls
submitToBlockchain()after local progress update when wallet is connected
- Calls
-
Updated Results Screen:
- Shows on-chain confirmation status:
- ✓ "Badge registrado on-chain" if minted successfully
- "Registrando on-chain..." while submitting
- "Conectá tu wallet para registrarlo on-chain" if not connected
- Error messages for duplicates/failures
- Shows on-chain confirmation status:
-
Added Imports:
useEffect,useState- React hooksuseStellarWallet- Check wallet connectionuseStellarProgress- Query on-chain badge status
-
Added State:
onChainBadges- Map of moduleId → has badge on-chainloading- Track badge status fetch
-
Added useEffect:
- Fetches on-chain badge status for all modules when wallet connects
- Calls
checkHasBadge(mod.id)for each module - Clears badges when wallet disconnects
-
Updated Badge Display Logic:
- When wallet connected: Use
onChainBadgesas source of truth - When wallet not connected: Use local progress
- Shows "On-chain" badge for confirmed NFTs
- Shows "Local" for earned but not yet minted
- Shows connection prompt at bottom
- When wallet connected: Use
The exact module IDs that will be passed to mint_badge contract:
| Module ID | Title | XP | Contract Call |
|---|---|---|---|
mod-1 |
¿Qué es DeFi? | 50 | mint_badge(address, "mod-1", "¿Qué es DeFi?", xp, score) |
mod-2 |
Smart Contracts | 150 | mint_badge(address, "mod-2", "Smart Contracts:", xp, score) |
mod-3 |
El Valor del Dinero... | 150 | mint_badge(address, "mod-3", "El Valor del Dinero...", xp, score) |
stellar-mod-1 |
La red Stellar | 50 | mint_badge(address, "stellar-mod-1", "La red Stellar", xp, score) |
stellar-mod-2 |
Introducción a Soroban | 150 | mint_badge(address, "stellar-mod-2", "Introducción a Soroban", xp, score) |
-
User completes quiz:
- Local progress saved via
progress.completeQuiz() - If wallet connected → blockchain submission starts
- Local progress saved via
-
Blockchain submission (if wallet connected):
- Check
hasBadge(module.id)→ skip if already minted - Call
reward_quizwith challengeId =${module.id}-quiz - If score >= 75 → Call
mint_badgewith actual XP earned - Refresh on-chain progress
- Show toast notification
- Check
-
Results screen:
- Shows NFT image
- Shows on-chain confirmation status
- If not connected → prompts to connect wallet
-
Achievements page:
- Queries
hasBadge(module.id)for each module - Shows "On-chain" badge for confirmed NFTs
- Falls back to local progress when wallet not connected
- Queries
The implementation handles:
- ✓ Duplicate quiz completion ("already completed")
- ✓ Duplicate badge minting ("already minted")
- ✓ Network errors (shows local save fallback message)
- ✓ Rate limiting (shows retry message)
- ✓ Wallet not connected (saves locally, prompts connection)
After applying changes:
- Save the
.vscode/settings.jsonfile - Replace QuizView.tsx with QuizView_NEW.tsx
- Replace EarnedNfts.tsx with EarnedNfts_NEW.tsx
- Verify no TypeScript errors
- Test quiz completion without wallet → should save locally
- Test quiz completion with wallet → should mint badge on-chain
- Test quiz retry after failure → should allow retry
- Test achievements page → should show on-chain badges when wallet connected
- Verify module IDs match exactly between courses.ts and contract calls
Ensure the backend has:
- ✓
ADMIN_SECRET_KEYenvironment variable set - ✓
/api/reward-quizroute working - ✓
/api/mint-badgeroute working - ✓ Badge NFT contract deployed at:
CDWJE7AM3DFWC6FD2RKBASWP7EITQ2ULJH4FX5JFQRVHXQSXDPJAB3KI
- ✅
mint_badgeis called on-chain afterreward_quizconfirms - ✅
checkHasBadgeis called before minting to avoid duplicate attempts - ✅
EarnedNfts.tsxuses on-chainhasBadgeas source of truth when wallet is connected - ✅ The
module_idexactly matches the IDs defined insrc/data/courses.ts - ✅ The quiz result screen only shows NFT confirmation if mint was successful or badge already exists
- ✅ Wallet not connected → shows badge in local UI with prompt to connect
- Save the
.vscode/settings.jsonfile (or close it without saving) - Run the commands above to replace the files
- Test the flow end-to-end
- Verify on-chain badges appear in the achievements page