Commit Graph

212 Commits

Author SHA1 Message Date
lemon b1ec7538b3 Mirror a real campaign and the live verified badge in the verify tutorial
The how-to demo card now reflects a real published campaign (the Agora
App Development Fund) instead of invented placeholder copy: real title,
organizer, banner image, and goal/progress. The verified badge is now a
faithful copy of the live overlay CampaignVerificationBadge (dark
translucent pill, ring-bordered avatar, sky-300 check, no count) for a
single verifier, so the preview matches exactly how a verification
surfaces on a real card.

Drops the now-unused demo i18n keys (campaignTitle, campaignOrganizer,
verifiedBadge) across all locales.
2026-06-14 16:03:33 -07:00
lemon 35ce3f87e1 Tighten verifier onboarding step subtitles 2026-06-14 16:03:33 -07:00
lemon 9640d8790f Preview verifier badge on the how-to step and tighten step copy
Remove the badge preview from the org bio step and surface it on the
'How to verify a campaign' step instead, where the demo card now shows
the org's own avatar + name in place of the generic 'Verified by you'
label. Shorten the tutorial step descriptions.
2026-06-14 16:03:33 -07:00
lemon ff3804777a Add 'Paste URL' option to org setup avatar and banner pickers 2026-06-14 16:03:33 -07:00
lemon 207775b6b9 Drop 'your' from verifier role finder note 2026-06-14 16:03:33 -07:00
lemon 528e87e9e4 Simplify the statement step; remove the editor from /organizations
Drop the 'Become a verifier' publish button: the statement step's primary
Continue button now publishes the kind 14672 statement and advances, with
an inline Withdraw for returning verifiers. Collapse the duplicated prompt /
disclaimer copy into a single header + subtext and make the editor
borderless. Replace the /organizations functional editor with a CTA that
launches the verifier onboarding flow.
2026-06-14 16:03:33 -07:00
lemon 716d3ee406 Mirror the verification badge in the bio-step preview
Replace the plain avatar+name+website header with a preview that mirrors the
inline verification badge (stacked avatar + check + name), so the user sees
how their logo and name will surface to donors. Drops the website from the
preview.
2026-06-14 16:03:33 -07:00
lemon 7ac8c58426 Make website replace the bio slot; relax identity requirements
Add a bioField prop to ProfileCard so the editable slot below the name can
edit the website instead of the bio. The verifier identity step now edits
the website inline (no separate input) and only requires avatar + name;
banner and website are optional, with website still https-validated when
entered.
2026-06-14 16:03:33 -07:00
lemon 9cc08c4989 Tighten role-picker copy to single lines
Shorten the verifier description so it fits on one line and update the
donor finder note to '100% of your donation goes to the campaign.'
2026-06-14 16:03:33 -07:00
lemon 900689acab Add verifier sub-flow step 1: organization identity
Build the organization-identity screen on the shared ProfileCard (circular
avatar, rectangular banner, inline name) plus ImageCropDialog for uploads,
with a dedicated required website field. All four fields are required and
the website must be a valid https URL before continuing. The draft is held
in the captive overlay and published later; nothing is written here.
2026-06-14 16:03:33 -07:00
lemon 77a50189d8 Add 'Verify campaigns' as a third onboarding role
Extend OnboardingRole and StartSignupOptions to include 'verifier', add a
third RoleCard to the role picker, and wire the pick handler to branch on
the new role. For now the verifier pick routes to the public /organizations
onboarding tool; a later commit replaces this with a captive sub-flow.
2026-06-14 16:03:33 -07:00
Barrett O. 886d3ece18 Add optional Tor (arti) routing on Android
Adds an opt-in Tor mode that routes all app traffic through a local
SOCKS5 proxy backed by arti (Tor in Rust), bundled via the
org.torproject:arti-mobile:1.7.0.1 AAR.

- TorController starts/stops arti and installs a fail-closed WebView
  proxy override (no direct fallback) so traffic can't leak while Tor is
  connecting or down. Connectivity is verified against
  check.torproject.org (IsTor) and re-checked continuously; the exit IP
  is surfaced for verification, and the status isn't latched so a dropped
  circuit downgrades honestly.
- TorPlugin bridges enable/disable/status to the Capacitor/JS layer.
  Toggling applies live, in place, with no app restart.
- UI: a slim fail-closed status banner (replacing the old full-screen
  gate), the Tor toggle in Advanced settings reachable while logged out,
  and Settings/Search/About added to the logged-out menu.
- R8 keep rules for org.torproject.arti.** so the JNI native-method
  classes aren't stripped/renamed; androidx.webkit on the compile
  classpath for the WebView proxy APIs.
2026-06-13 16:26:58 +00:00
Alex Gleason e196227a23 Add animated verify-campaign tutorial after publishing statement
Once an organization publishes its verifier statement on /organizations,
show an interactive walkthrough demonstrating how to verify a campaign:
a looping three-step animation on a mock campaign card where a cursor opens
the three-dots menu and selects 'Verify this campaign'. Step list is
clickable to scrub; motion is gated behind prefers-reduced-motion.
2026-06-12 16:00:35 -05:00
Alex Gleason d0d315a9b2 Add 'Verified' tab to verifier profiles, defaulting to it
Verifier profiles (accounts with a kind 14672 statement) now get a
'Verified' tab listing the campaigns they have vouched for, resolved
from the account's own agora.verified (kind 1985) labels via the new
useVerifiedCampaigns hook. The tab is surfaced first and becomes the
default on initial load (without overriding a manual tab selection),
on both desktop and mobile. Non-verifiers never see the tab.

Adds ProfileVerifiedTab, the useVerifiedCampaigns hook, and profile.tabs
/ profile.verified i18n keys across all locales.
2026-06-12 15:19:33 -05:00
Alex Gleason 34556ceed2 Move verifier statement full-width above profile tabs
Surface a verifier's kind 14672 statement as a full-width band above the
profile tabs (below the header) on both desktop and mobile, instead of
tucked into the left identity rail / overview tab.

Drop the shield-check icon and rename the heading to 'How We Verify' —
the statement is a self-authored claim, not a platform endorsement, so
the heading stays neutral with no trust-implying badge. Rename the
verifier.profileSectionTitle key to verifier.howWeVerifyTitle across all
locales.
2026-06-12 14:50:49 -05:00
Alex Gleason 706a3ef2eb Remove 'Why it matters' section from /organizations
Drop the benefit-cards section between the steps and the editor, along
with the now-unused BenefitCard component, Users/Eye/cn imports, and the
organizations.why.* i18n keys across all locales.
2026-06-12 14:32:57 -05:00
Alex Gleason 43fecb6e6f Add WYSIWYG markdown editor for verification statements
Restore the deleted Milkdown WYSIWYG editor (its deps and CSS were still
installed) as a reusable component under src/components/markdown/:
MilkdownEditor, a formatting toolbar (bold/italic/headings/lists/links/
quote/code/hr + markdown help popover), and an insert-link dialog. All
strings are now i18n-driven via a new mdEditor locale block, translated
across every locale.

Wire it into the /organizations verifier-statement editor, replacing the
raw textarea + separate live preview with rich-text editing that emits
markdown. Fix the editor placeholder so it only shows while empty by
toggling a has-content class on the ProseMirror DOM.
2026-06-12 14:29:08 -05:00
Alex Gleason 33852f60fb Redesign /organizations as a marketing + onboarding landing page
Rework the /organizations page to match the /about landing style so it
doubles as marketing and a functional tool: a dark world-map hero with a
scroll-to CTA, a three-step onboarding section, benefit cards, and a
'get started' section housing the verifier-statement editor. Logged out
shows the org-profile login gate; logged in shows the full publish /
update / withdraw editor.

Move the route to the wide FundraiserLayout so section backgrounds span
the viewport, and expand the organizations i18n block (hero, steps, why,
getStarted) across all locales.
2026-06-12 14:16:03 -05:00
Alex Gleason 2e5d160a9e Add /organizations onboarding page, move verifier form off settings
Replace the /settings/verifier route with a public /organizations help
page that onboards organizations onto Agora. Logged-out visitors are
prompted to log in with — or create — their organization's Nostr
profile; once signed in they get the full verifier-statement editor
that previously lived under settings.

Remove the Verifier entry from the settings list, delete
VerifierSettingsPage, and link /organizations from the site footer
instead. The old /settings/verifier path now redirects to
/organizations.
2026-06-12 14:06:24 -05:00
Alex Gleason e67c5dba75 Fix Settings header alignment and trim verbose copy
- Add an opt-in contentClassName to PageHeader so a page can constrain the
  header row to the same centered column as its body. Settings sub-pages now
  pass max-w-2xl/max-w-xl so the title and back arrow line up with the cards
  instead of floating against the viewport edge.
- Drop the entire header from the Settings hub (no title/back arrow); the
  grouped card list now reads the same on mobile and desktop.
- Remove redundant subtitles and intro blurbs from Appearance, Language,
  Network, Advanced, Profile, and Notifications.
- Delete the now-orphaned i18n keys across all locales.
2026-06-12 13:24:49 -05:00
Alex Gleason e8a9f679f9 Redesign Settings with Apple-inspired grouped UI
Rework the Settings hub and sub-pages into iOS-style grouped inset cards:
- Hub groups rows into Account / App / System sections, each row gets a
  colored gradient icon tile, with a rounded bg-card container and hairline
  dividers instead of the flat full-width list.
- Appearance and Language pickers use the same inset-card list rather than
  bordered selectable buttons.
- Network and Advanced replace the heavy accent-bar section headers with
  uppercase group labels above clean bg-card panels.
- Add settings.groups.{account,app,system} strings across all locales.
2026-06-12 13:00:13 -05:00
Alex Gleason b271c4e889 Add verifier statements (kind 15063)
Anyone can become a verifier by publishing a kind 15063 replaceable
event whose Markdown content describes how they vet campaigns. The
statement is surfaced prominently in the profile overview so donors
can judge whether to trust the account's judgement.

- Document kind 15063 in NIP.md
- useVerifierStatement / useSetVerifierStatement hooks (read-modify-write)
- /settings/verifier form page with live preview, publish/withdraw
- ProfileVerifierSection rendered first in the profile overview
- Localize all strings across every locale
2026-06-12 12:42:50 -05:00
Alex Gleason c9d77d06a1 Rename "activist" to "recipient" in donation copy
The people receiving donations are not necessarily activists — they are
often simply people in need (e.g. in Venezuela and Gaza). Rename the
user-facing term from "activist" to "recipient" across all copy and the
underlying code.

- Rename ActivistGuidePage -> RecipientGuidePage and the /about/activists
  route -> /about/recipients (legacy URL kept as a redirect).
- Rename guide structure/helpers, the paymentComparison audience literal,
  and the related i18n key namespaces (activistGuide -> recipientGuide,
  about.guides.activist -> .recipient, guides.activist -> guides.recipient,
  activistRows/activistHeader -> recipientRows/recipientHeader,
  ctaActivist -> ctaRecipient).
- Translate the term in all 16 locales, plus fix stale "activists" hero
  taglines left over from 0233a75d in id/hi/sw/tr/zh-Hant.
2026-06-10 15:43:08 -05:00
Alex Gleason 0233a75d5c Update hero tagline from 'activists' to 'the world' 2026-06-10 10:43:43 -05:00
Alex Gleason 8473a4990f Scan for silent payments automatically in the background
Lift the silent-payment orchestrator into an HdWalletSpProvider mounted at
the app root so a single shared scan instance keeps running across page
navigation. Add a background auto-scanner that resumes from the last
persisted scanHeight and keeps up with the chain tip without any user
action, bounding the first pass on a never-scanned wallet to ~7 days of
blocks. Surface live scan state on the Private wallet tab and add an
auto-scan toggle to the scan dialog.
2026-06-08 16:11:54 -05:00
Alex Gleason e5277f004e Show verification badge on campaign detail page
Add an inline variant of CampaignVerificationBadge that reads on a light
page surface (bordered chip with a 'Verified' label) and render it next to
the author byline in the campaign detail heading. The overlay variant (dark
pill) is unchanged for cards over banners.

New i18n key campaignVerification.verifiedLabel across all locales.
2026-06-06 19:24:27 -05:00
Alex Gleason 93bcf04ae9 Confirm campaign verification through a dialog
Clicking 'Verify this campaign' now opens a VerificationDialog instead of
publishing immediately. The dialog previews the moderator's own avatar
with the verification checkmark (as it appears on verified campaign cards)
and shows the attestation the moderator is making before confirming.

- New VerificationDialog component (avatar + checkmark preview + attestation
  text + Cancel / Verify actions).
- ModerationMenu owns the dialog state and the verify mutation, hoisted out
  of the dropdown content (which unmounts on select) like the existing
  add-to-list dialog; passes onRequestVerify down to CampaignVerifyItem.
- Removing a verification stays inline (no confirmation).
- New i18n keys dialogTitle + attestation across all locales.
2026-06-06 19:18:39 -05:00
Alex Gleason f95ab1b422 Treat campaign verification as a moderator action
Verification is gated by the existing campaign moderator pack
(useCampaignModerators / CAMPAIGN_MODERATORS), not a separate allowlist.

- Remove the config.labelers field (AppContext interface, Zod schema,
  App.tsx and TestApp defaults) and delete useCampaignLabelers.
- useCampaignVerifications now reads/writes agora.verified labels gated
  on the moderator pack (isModerator), same authors filter as the other
  label streams.
- Move the verify / remove-verification row INSIDE the moderation kebab's
  'Moderator actions' section (leadingExtra slot of ModerationItemsShell),
  no longer a top-level item above the section label.
- Revert the isMod || isLabeler widening in ModerationMenu/Overlay back to
  plain isMod.
- Remove the trailing 'Verified' checkmark text from 'Remove my
  verification'.
- Rename labeler->moderator in agoraVerification, the badge component, and
  all locale strings; drop now-unused notVerified / verifiedState keys.
- Update NIP.md to document verification as a moderator action.
2026-06-06 19:11:48 -05:00
Alex Gleason 1557e2fff9 Move campaign verify action into moderation kebab menu
The verify / remove-verification controls now live as rows in the
campaign 'Moderator actions' 3-dots menu instead of inside the
verification badge popover. The badge over the card is now display-only
(stacked verifier avatars + a popover listing them, linking to profiles).

Because labelers are a distinct allowlist from the moderator pack, the
campaign moderation menu/overlay now mounts for a user who is a mod OR a
labeler; the verify row itself is gated on labeler membership, while the
hide/add-to-list rows stay moderator-only.
2026-06-06 18:50:00 -05:00
Alex Gleason b8c1bc7409 Add agora.verified campaign verification labels
Trusted labelers (AppConfig.labelers) can vouch for campaigns via NIP-32
kind 1985 labels in the new agora.verified namespace. Verifier avatars
render as a stacked badge on campaign cards; hovering/clicking opens a
popover listing verifiers (linking to their profiles). Logged-in labelers
get verify / remove-verification controls — verify publishes a label,
unverify issues a kind 5 deletion of their own label.

The read query filters by authors: labelers so verifications from outside
the allowlist are never honored. Kind 1985 label reqs are routed to the
search relays (relay.ditto.pub, relay.dreamith.to) in NostrProvider.
2026-06-06 18:06:36 -05:00
mkfain 872e8428d2 Source home hero row from Featured Campaigns list
Switch the home-page hero row from the World Liberty Congress curated
list (d=world-liberty-congress) to the Featured Campaigns list
(d=featured-campaigns), both curator-published kind-30003 NIP-51
bookmark sets.

Replace the WLC org-branded heading (avatar, name, npub profile link
pulled via useAuthor) with a plain 'Featured Campaigns' heading that
links to /campaigns/lists/featured-campaigns. Drop the now-unused
Avatar / useAuthor / genUserName imports and the WLC pubkey/npub
constants.

Rename the WLC_* constants to FEATURED_* and replace the wlcDesc
locale key with featuredTitle + featuredDesc across all 16 locales.
2026-06-05 17:04:55 -05:00
Alex Gleason a2dd16fc94 Merge branch 'main' of gitlab.com:soapbox-pub/agora 2026-06-05 16:46:39 -05:00
Alex Gleason 0c455c6d6f Block public-wallet sends to your own silent payment address
Sending from the public (BIP-86) wallet to your own silent payment
address co-mingles the resulting silent-payment UTXOs with coins
already exposed on the public ledger, linking the private wallet back
to a known on-chain identity and defeating its purpose.

Unlike the private-wallet reuse guard (which offers a 'send anyway'
acknowledgement), this is disallowed outright: the Send button stays
disabled and a blocking notice explains why.
2026-06-05 16:33:00 -05:00
mkfain f0af799647 Document Public/Private wallet split in About and guides
The previous commit split the wallet into strictly-isolated Public
(BIP-86) and Private (silent-payment) balances that can never be spent
together. Update the user-facing docs to match:

- /about: the Silent Payments card now notes private funds are kept in
  a separate balance, never mixed with public ones.
- Activist Guide: the receiving section explains the Public/Private tabs
  and why mixing would re-link silent-payment donations; a new callout
  covers cashing out from the Private tab to an sp1… address and the
  'Send anyway' address-reuse guard; the cash-out intro now points at
  the Private tab.
- Wallet FAQ: notes the two strictly-separated tabs.

All copy mirrored across the 15 non-English locales.
2026-06-05 15:47:53 -05:00
Alex Gleason 4cd725daf1 Merge branch 'main' of gitlab.com:soapbox-pub/agora 2026-06-05 15:19:25 -05:00
Alex Gleason e7439611b1 Separate wallet into isolated Public and Private wallets
Silent-payment (private) UTXOs were combined with BIP-86 (public) UTXOs
during coin selection, and silent-payment change was sent to a public
BIP-86 change address. Both linked private funds back to the public
wallet on-chain, defeating the unlinkability silent payments exist to
provide.

Enforce strict UTXO isolation at the PSBT-build layer: a spend now
carries a `walletScope` and the coin selector only ever sees the matching
input kind (public → BIP-86, private → SP). Private-wallet change is
routed to a fresh BIP-352 output back to the wallet's own sp1 address, so
it re-enters the private wallet instead of leaking to a public change
address. The two UTXO sets can no longer be spent together.

Surface the separation as Public / Private tabs on /wallet, each with its
own balance, receive QR (bc1 vs sp1), send flow, and transaction history.
Private sends to a bare on-chain address are gated by an address-reuse
guard: when the recipient chip is selected, a Blockbook getAccountInfo
probe checks for prior on-chain history, and the address is also checked
against the user's own public wallet. Either case requires an explicit
"Send anyway" acknowledgement; the Send button is disabled while the
probe is in flight. Sending a silent payment to an sp1 address has no
such warning.
2026-06-05 15:18:51 -05:00
mkfain 168ca2d067 Drop "Plain English, no walls of text." from activist guide subtitle 2026-06-05 13:57:59 -05:00
Chad Curtis 79c6e7e516 Translate replies/comments header and count on post detail
The replies section heading ('Replies'/'Comments') and the count noun
('reply'/'replies'/'comment'/'comments') were hardcoded English literals
adjacent to the placeholder fixed in the previous commit. Move them to a
new postDetail locale section with i18next plural keys, translated across
all locales.
2026-06-02 09:03:20 -05:00
Chad Curtis 9717a6827f Fix untranslated reply composer placeholder on post detail
The placeholder used a hardcoded 'Write a reply...' literal and referenced
a nonexistent compose.activityPlaceholder key (which fell back to the raw
key string). Switch to translated replyModal.placeholder.writeReply /
writeComment keys and add writeReply to all locales.
2026-06-02 08:57:55 -05:00
Chad Curtis e7c488af63 Add Zapstore app download nudge
Prompt mobile-web visitors to install the native Android app from
Zapstore. Shows a card at the bottom of the home feed and a link in
the account switcher menu. Both are hidden inside the native app
(Capacitor.isNativePlatform) and on desktop (sm:hidden for the banner).

Adds nav.getApp and feed.getApp.* strings across all locales.
2026-06-02 08:40:58 -05:00
lemon 4153792e54 Add missing Why Agora translations 2026-06-02 04:29:26 -07:00
Chad Curtis a5cc9c5163 Break walletHeroNote onto two lines 2026-06-02 04:24:57 -05:00
Chad Curtis 5d4d0825c6 Remove "no payout setup" from wallet hero note copy 2026-06-02 04:10:33 -05:00
Chad Curtis 123f53e7a6 campaigns: carry public/private framing into custom wallet mode
Switching to a custom (manual-entry) wallet used to drop the friendly
accept picker entirely, leaving two unlabeled-purpose address inputs.
Restore the hand-holding: add an intro line restating the field-driven
model (public address, private code, or both) and label each input
with its meaning. The public/on-chain input is marked with a Bitcoin
icon and a 'Public. Anyone can see these donations.' caption; the
silent-payment input with an EyeOff icon and a privacy caption. Both
inputs keep the Wallet leading icon. Updates all 16 locales.
2026-06-02 01:59:44 -05:00
Chad Curtis 977fd000ea campaigns: make the donation-accept picker friendlier
Replace the three terse jargon pills (Accept All / Public Only /
Private Only, captioned with 'on-chain' and 'silent payment') with a
vertical stack of selectable option cards. Each card has a friendly
icon, a plain-language title, and a one-sentence reassurance written
for an anxious first-time creator, with the SP-dependent options
clearly disabled when the login can't support them.

Also softens the wallet hero card: drop the linked-icon trio for a
simple campaign-to-wallet arrow, and rewrite the copy without the
key/posts technical aside or em dashes. Updates all 16 locales.
2026-06-02 01:59:44 -05:00
Chad Curtis 5132141aa2 campaigns: give the wallet step a hero coupling card
Redesign the 'My wallet' branch of the campaign wizard's donation
destination step. Replace the plain identity+balance row with a
primary-tinted hero card modelled on the onboarding 'Save your key'
surface: a linked-icon trio (campaign -> key -> wallet) explains that
donations land in the creator's own Agora wallet unlocked by the same
key that signs their posts, with the avatar+live-balance chip
confirming the exact destination and a ShieldCheck reassurance line
below.
2026-06-02 01:59:44 -05:00
Chad Curtis b6dc57eb85 Merge branch 'feat/send-MAX' into 'main'
Feat/send max

See merge request soapbox-pub/agora!40
2026-06-02 06:36:55 +00:00
mkfain d4cf4ba0d8 campaigns: collapse curated lists strip after first 5 pills 2026-06-02 00:28:08 +02:00
lemon c97d0723a6 wallet: add max send option 2026-06-01 15:18:12 -07:00
Chad Curtis c79699ca71 campaigns: remove deadline from events and form
Drop the optional `deadline` tag from kind 33863 campaigns. Removes the
date input and validation from the create/edit form, the deadline chips
on the card, detail, and inline-preview surfaces, and the derived
"ended" state that disabled donations after the deadline. Cleans up the
associated locale keys and NIP.md documentation.
2026-06-01 17:03:30 -05:00