+ ) : (
+ <>
+ {/* Exchange Card */}
+ {(showExchange || exchangeState !== 'idle') && (
+
+ {exchangeState === 'idle' && (
+
+
Claim via VC-API
+
Paste a credential offer URL to start an exchange.
+
+
+ setExchangeUrl(e.target.value)}
+ />
+
+
+
+
+
+ {exchangeError &&
{exchangeError}
}
+
+ )}
+
+ {exchangeState === 'contacting' && (
+
+
Contacting issuer…
+
Fetching credential offers from the issuer.
+
+
+
+
+ )}
+
+ {exchangeState === 'offer' && (
+
+
Select credentials to claim
+
+ {exchangeOffers.map((vc, i) => {
+ const typedVc = vc as MinimalVc;
+ const title = getTitleFromVc(typedVc);
+ const issuer = getIssuerNameFromVc(typedVc);
+ const isOpen = offerOpenCatIdx === i;
+ const cat = offerCategories[i] || 'Achievement';
+ return (
+
+
{
+ const next = offerSelected.slice();
+ next[i] = e.target.checked;
+ setOfferSelected(next);
+ }}
+ />
+
+
+
{title}
+
{issuer ? `by ${issuer}` : ''}
+
+
setOfferOpenCatIdx(i)}
+ onClose={() => setOfferOpenCatIdx(null)}
+ onSelect={(value) => {
+ const next = offerCategories.slice();
+ next[i] = value;
+ setOfferCategories(next);
+ setOfferOpenCatIdx(null);
+ }}
+ />
+
+ );
+ })}
+
+
+
+
+
+
+
+ )}
+
+ {exchangeState === 'saving' && (
+
+
Claiming…
+
Saving credentials to your LearnCard wallet.
+
+ )}
+
+ {exchangeState === 'success' && (
+
+
Success
+
Credentials were added to your inbox below. You can now manage them like other detections.
+
+
+
+
+ )}
+
+ {exchangeState === 'error' && (
+
+
Something went wrong
+
{exchangeError ?? 'Unknown error'}
+
+
+
+
+ )}
+
+ )}
+
+ {/* Inbox */}
+ {!(showExchange || exchangeState !== 'idle') && ((
+ (hideClaimed
+ ? candidates.map((_, i) => i).filter((i) => !candidates[i]?.claimed)
+ : candidates.map((_, i) => i)
+ ).filter((i) => candidates[i]?.source !== 'link')
+ ).length > 0 ? (
+