* feat: add cards directory page with provider listings
Adds a dedicated Cards screen that surfaces crypto debit card
providers users can top up from their Alby Hub balance, with region
and feature filters and a fees comparison table.
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(cards): connect-card flow with NWC top-up link
Iterates on the cards directory page (#ae087d0b) to wire up the full
connect-card flow described with the bitcoin-card-topup PWA at
card.albylabs.com.
- AI-style hero with three steps: Get a card → Connect it → 1-click top-ups
- Trimmed provider list to RedotPay / 2fiat / Freedomia (the providers
we've validated end-to-end)
- New "Time to get" column so users see physical vs virtual at a glance
- Renamed "Add card" → "Connect card" everywhere; submit mints a real
NWC connection via createApp (same pattern as the AI page) with
scopes for the topup app (get_info / get_balance / list_transactions /
lookup_invoice / make_invoice / pay_invoice / notifications)
- CardCreatedDialog shown once at creation with QR code + bookmarkable
top-up link of the form
https://card.albylabs.com/#label=...&address=0x...&chainId=42161¤cy=USDC&nwc=<pairing-uri>
Includes prominent "save this link — you won't see it again" warning
(Alert with warning variant) and "scan with your phone's camera app
(this is a URL, not a Lightning invoice)" caption under the QR
- Saved card tiles link to /apps/:appId so users get back to the NWC
connection detail; no separate top-up affordance from the hub
- useUserCards hook persists cards in localStorage with appId pointing
at the NWC connection; ready to migrate to deriving the list from
/api/apps filtered by metadata.app_store_app_id = "bitcoin-card-topup"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(cards): derive cards from /api/apps, polish
Replaces the localStorage card store with a derivation from /api/apps
filtered by metadata.app_store_app_id = "bitcoin-card-topup". Card
provider/destination/chain/currency now ride on the NWC app's metadata,
so cards survive across devices, reloads and DB backups, and "forget
card" flows through the existing /apps/:id delete affordance.
- Gate /cards through DefaultRedirect so a locked hub redirects to
/unlock (matches /wallet, /apps, etc.)
- Hub-generated top-up link now uses #?... prefix so bitcoin-connect's
parser branches to the URLSearchParams path (works in all cases vs.
the bare #... which mis-parsed for some users)
- Remove EmptyCards empty state (the Connect card button in the page
header is the sole entry point)
- Drop the "Experimental" filter and badge — too small a catalog for
it to be useful, and the toggle behavior confused users
- Replace "Top up via" column with "Card cost" (more decision-relevant)
- Verified all provider data from each provider's site; updated
- RedotPay: KYC Full (not Light), regions add US/UK, fees ~2.2% + FX
- 2fiat: Mastercard (not Visa), Apple Pay + Google Pay supported, KYC
None (not Light), card cost $50, fees ~6.8%
- Freedomia: Google Pay supported, card cost $5–30/mo subscription,
fees 1.3–4.3%
- Add a hoverable info-icon tooltip on the "None" KYC badge so privacy-
focused users keep the signal they want while cautious users see the
merchant-of-record-fragility caveat
- Field label "Destination address" → "Top-up address" (matches what
the user pastes from their provider)
- Connect dialog copy de-emdashed
- Various smaller copy/layout tweaks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(cards): tidy provider tiles, filter, and column header
- Switch Freedomia tile bg to bg-orange-500 to match the brand's
orange F logo
- Drop the upscaled watermark logo from card-tile backgrounds for a
cleaner surface
- Hide filter toggles whose criterion no provider satisfies, so the
filter bar only offers actionable options
- Rename "Mobile pay" column header to "Mobile" — the icons already
identify Apple/Google Pay
Co-Authored-By: Claude <noreply@anthropic.com>
* chore(cards): drop unused provider logos
We trimmed the catalog to RedotPay/2fiat/Freedomia in an earlier
commit; the other 8 PNGs were left behind. Remove them to keep the
asset directory tight.
Co-Authored-By: Claude <noreply@anthropic.com>
* chore(cards): downgrade RedotPay KYC from Full to Light
RedotPay only requires ID verification — no proof of address, employer
details, or source-of-funds questions. "Full" overstates it and may
deter users from even trying.
Adds a Light KYC tooltip alongside the existing None one so the
distinction is visible at a glance.
* chore(cards): tighten copy and mobile layout
- CardCreatedDialog: drop the "regular URL, not a Lightning invoice"
caveat and replace with actionable "save it as an app to your
homescreen" guidance.
- Hide the QR + scan instruction on mobile — the user is already on
their phone, so scanning their own screen is nonsense.
- Provider table: switch wrapper from overflow-hidden to overflow-x-auto
and set a 720px min-width so 9 columns scroll horizontally on narrow
viewports instead of cramming/clipping.
* feat(cards): list Bringin and wavecard
Both already ship as suggested apps with their own NWC pairing flows, so
the table row's action arrow links to /appstore/<id> rather than the
stablecoin connect-card dialog. Marked via a new optional appStoreId
flag on Provider; the Connect-card dropdown filters these out so the
top-up form never offers a chain/currency for cards that don't need one.
Reuses the existing suggested-apps logos to avoid duplicating assets.
* chore(cards): retitle 3rd hero step to highlight top-up speed
"Top up in seconds — your card is funded in under a minute, ready to
spend on the go" lands the speed promise harder than "1-click top-ups"
did, and frames the value as on-the-go spending rather than mechanics.
* feat(cards): route app-store cards through the Connect dialog
Bringin and wavecard are now in the provider dropdown. Picking either
hides the address/network/currency fields and replaces the primary
button with an "Open setup guide" link to /appstore/<id>, where their
own NWC pairing flow lives. Keeps a single entry point for "connect a
card" without forcing the stablecoin form onto cards that don't use it.
Also tightens the hero subtitle to lead with the speed promise.
* chore(cards): link app-store cards straight to /apps/new
Skip the app-store detail page — /apps/new?app=<id> drops users into
the connection flow with the right app preselected, which is what they
actually wanted.
* chore(cards): correct Bringin and wavecard table data
Verified against bringin.app/bitcoin-debit-cards and wave.space/card:
- Both offer physical *and* virtual cards (added "Both" to cardType).
- wave.space is EEA-only for issuance (card itself is accepted globally)
— regions changed from Global to EU.
- Direct Apple Pay isn't live for either; both currently work via Curve,
which is too indirect to claim native Apple Pay support.
- Issuance is not free: Bringin charges a €3.49/mo subscription that
bundles both cards; wave.space charges €2.99 virtual / €29.99 physical
one-time.
- Conversion fees are 1% + ~0.5% LP spread for both, not flat ~1%.
- Bringin URL fixed to bringin.app (they migrated from bringin.xyz);
wave.space URL points at the card landing page.
Doesn't change the dialog routing — picking Bringin/wavecard still drops
the user into /apps/new?app=<id> for the NWC pairing.
* chore(cards): tighten created-dialog copy
- Title and subtitle now describe the link instead of warning.
- Alert highlights the device-specific action ("save it on the phone
you'll top up from") and drops the redundant secret-recovery prose.
- QR caption mentions bookmark as an alternative to home-screen install.
* refactor(cards): route every provider through the standard app flow
- Add a bitcoin-card-topup app store entry pointing to card.albylabs.com
with a "visit + add to home screen + enter card details" install guide.
- Wire RedotPay and Freedomia to bitcoin-card-topup, and 2fiat to its
existing app store entry. Bringin and wavespace already had theirs.
- Drop the custom Connect card dialog, address/network/currency form,
and the one-shot CardCreatedDialog with embedded NWC link. Card config
is now collected inside the topup app itself.
- Drop the "Your card connections" section and the useUserCards hook —
connected cards show up in the standard /apps list like any other app.
* feat(cards): add Connect card picker dialog + clickable rows
- Bring back the Connect card button in the header; opens a lightweight
provider-picker dialog where each tile routes straight to
/apps/new?app=<appStoreId>.
- Drop the table's action column entirely; the whole provider row is now
clickable and opens the provider's website in a new tab. This separates
discovery (row click → learn more) from action (Connect card → setup).
* feat(cards): add Other card option + broaden install wording
- Add an "Other card" tile to the Connect card picker (dashed border,
generic credit-card icon). Routes to /apps/new?app=bitcoin-card-topup
so anyone holding a USDC/USDT card not in the listed providers can
still set up the topup flow.
- Reword the install guide from "phone you'll top up from" to "device" —
the topup app works equally well on a tablet or any browser.
* chore(cards): fix bitcoin-card-topup logo + broaden copy to "any crypto"
- Swap the placeholder 2fiat logo for the Alby logo (alby.png).
- Drop USDC/USDT specifics from the app description, extended
description, and the picker dialog's "Other card" tile copy. From the
user's perspective the topup app just takes a crypto card.
* chore(cards): use bitcoin-card-topup's own PWA icon as the app logo
Copy bitcoin-card-topup/public/shortcut-icon.png (the topup PWA's home-
screen icon) into suggested-apps/ and point the bitcoin-card-topup app
store entry at it, replacing the Alby-logo placeholder.
* fix(apps): align Connect-to-app header logo size with the appstore page
NewApp.tsx rendered the app logo at w-12 h-12 (48px) while
AppStoreDetailHeader uses w-14 h-14 (56px) — the logo visually jumps
between /apps/new?app=<id> and /appstore/<id>. Unify on w-14 h-14.
* fix(appstore): use AppHeader's standard icon/description slots
AppStoreDetailHeader was rendering the logo + title + description inside
a custom flex container nested into AppHeader's title prop, which gave
the icon a different vertical alignment than every other AppHeader use.
Pass them via the icon and description props instead so the header
layout stays consistent with /apps/new and the rest of the app.
* chore(cards): use Freedomia affiliate URL
* chore: add affiliate links
* fix: always show global cards
* fix: make 2fiat lightning native
* chore: update card instructions
* chore: optimize bitcoin card topup app image
* chore: improve bitcoin card topup copy
* chore: add card events, fix http service event endpoint url
* chore(cards): drop redundant 'Get a card' section heading
* chore(cards): tighten hero subtext + 3-step copy, hide filter footer when inactive
- Hero subtext drops the "one click" claim that's no longer accurate
post-refactor and the em-dash.
- 3-step descriptions reworded for length and fix "Setup" -> "Set up";
bottom step matches the "in seconds" heading instead of saying
"under a minute".
- "Showing N of M providers" footer is hidden unless a filter is
active — silent when there's nothing to clarify.
* chore(cards): apply Alby button gradient + brand stroke to hero card
Use the same vertical white→cream highlight and 1px #ffdf6f stroke that
alby.css applies to default primary buttons, so the hero card visual
reads as part of the same theme family instead of an isolated panel.
* chore(cards): reframe step 2 around the top-up link + drop hero gradient
- Step 2 title shifts from "Connect it" to "Get a top-up link" so the
deliverable (a saveable link) is what users see, matching what
actually happens at that step post-refactor.
- Drop the white→cream gradient overlay from the hero card; the flat
yellow with the existing shadow is the look we want.
* chore: change wave.space kyc level
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>