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.
This commit is contained in:
lemon
2026-06-12 20:39:31 -07:00
parent 92091c8570
commit b1ec7538b3
17 changed files with 91 additions and 112 deletions
+75 -48
View File
@@ -7,6 +7,7 @@ import {
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { sanitizeUrl } from '@/lib/sanitizeUrl';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
/**
@@ -247,6 +248,23 @@ export function VerifyTutorial({
// ── The animated mock card ───────────────────────────────────────────────
/**
* A real published campaign (kind 33863) used as the demo subject so the
* tutorial mirrors an actual card rather than invented placeholder copy.
* Static by design — the tutorial is purely illustrative, so we read the
* fields directly instead of fetching the event.
*/
const DEMO_CAMPAIGN = {
title: 'Agora App Development Fund',
organizer: 'Team Soapbox',
story: 'Help fund the development of Agora!',
banner:
'https://blossom.primal.net/aade02e86584a7ab269550992d0266bae31059a34e6e08fddba1f6f5acb6e7d6.jpg',
goalLabel: '$1,000',
raisedLabel: '$670',
pct: 67,
} as const;
interface DemoStageProps {
phaseIndex: number;
menuVisible: boolean;
@@ -270,11 +288,16 @@ function DemoStage({
}: DemoStageProps) {
const { t } = useTranslation();
// When a verifier identity is supplied, the badge mirrors the live
// verification badge (org avatar + name); otherwise it falls back to the
// generic "Verified by you" label.
const hasVerifier = !!verifierName?.trim();
const verifierInitial = verifierName?.trim()?.[0]?.toUpperCase() ?? '?';
// The badge replicates the live overlay `CampaignVerificationBadge`
// (dark translucent pill, single ring-bordered avatar, sky check) so the
// preview matches exactly how a verification surfaces on a real card.
const badgePicture = sanitizeUrl(verifierPicture);
const verifierInitials =
(verifierName?.trim() || '')
.slice(0, 2)
.toUpperCase() || '?';
const bannerUrl = sanitizeUrl(DEMO_CAMPAIGN.banner);
return (
<div
@@ -284,52 +307,41 @@ function DemoStage({
)}
aria-hidden="true"
>
{/* Mock campaign card */}
{/* Mock campaign card — mirrors CampaignCard's structure. */}
<div className="overflow-hidden rounded-2xl border border-border/60 bg-card shadow-md">
{/* Banner */}
<div className="relative h-40 bg-gradient-to-br from-sky-500/80 via-cyan-500/70 to-emerald-500/80">
<div
className="relative h-40 bg-gradient-to-br from-sky-500/80 via-cyan-500/70 to-emerald-500/80 bg-cover bg-center"
style={bannerUrl ? { backgroundImage: `url("${bannerUrl}")` } : undefined}
>
{/* Top scrim for badge legibility — as on the real card. */}
<div
aria-hidden
className="absolute inset-0 opacity-30 mix-blend-overlay"
style={{
backgroundImage:
'radial-gradient(circle at 30% 30%, rgba(255,255,255,0.5), transparent 45%)',
}}
className="absolute inset-x-0 top-0 h-16 bg-gradient-to-b from-black/30 to-transparent"
/>
{/* Verified badge (top-left) — appears in the final phase. When a
verifier identity is supplied it previews that org's avatar +
name; otherwise a generic "Verified by you" label. */}
{/* Verified badge (top-left) — appears in the final phase. A faithful
copy of the live overlay CampaignVerificationBadge for a single
verifier: the org's avatar + sky check, no count text. */}
<div
className={cn(
'absolute left-3 top-3 flex items-center gap-1.5 rounded-full bg-background/90 text-xs font-semibold text-foreground shadow-sm backdrop-blur transition-all duration-500',
hasVerifier ? 'py-1 pl-1.5 pr-2.5' : 'px-2.5 py-1',
'absolute left-3 top-3 z-10 inline-flex items-center gap-1 rounded-full bg-black/40 px-1.5 py-1 text-white backdrop-blur-md transition-all duration-500',
verified
? 'opacity-100 translate-y-0'
: 'opacity-0 -translate-y-1 pointer-events-none',
)}
>
{hasVerifier ? (
<>
<Avatar className="size-5 shrink-0 ring-2 ring-background">
<AvatarImage
src={verifierPicture || undefined}
alt={verifierName}
className="object-cover"
/>
<AvatarFallback className="bg-secondary text-[9px] font-semibold text-secondary-foreground">
{verifierInitial}
</AvatarFallback>
</Avatar>
<BadgeCheck className="size-4 text-primary" />
<span className="max-w-[10rem] truncate">{verifierName}</span>
</>
) : (
<>
<BadgeCheck className="size-4 text-primary" />
{t('organizations.tutorial.demo.verifiedBadge')}
</>
)}
<span className="flex items-center -space-x-2">
<Avatar className="size-6 ring-2 ring-background">
{badgePicture && <AvatarImage src={badgePicture} alt="" className="object-cover" />}
<AvatarFallback className="bg-secondary text-[9px] text-secondary-foreground">
{verifierInitials}
</AvatarFallback>
</Avatar>
</span>
<span className="ml-0.5 inline-flex items-center gap-1 pr-1 text-xs font-semibold">
<BadgeCheck className="size-4 text-sky-300" />
</span>
</div>
{/* Three-dots button (top-right) */}
@@ -373,23 +385,38 @@ function DemoStage({
{/* Card body */}
<div className="space-y-3 p-4">
<div>
<p className="font-semibold leading-snug">
{t('organizations.tutorial.demo.campaignTitle')}
<p className="font-semibold leading-snug truncate">
{DEMO_CAMPAIGN.title}
</p>
<p className="text-xs text-muted-foreground">
{t('organizations.tutorial.demo.campaignOrganizer')}
<p className="text-xs text-muted-foreground truncate">
{DEMO_CAMPAIGN.story}
</p>
</div>
{/* Fake progress bar */}
{/* Progress — mirrors CampaignProgress (bar + raised / goal). */}
<div className="space-y-1.5">
<div className="h-2 w-full overflow-hidden rounded-full bg-muted">
<div className="h-full w-2/3 rounded-full bg-primary" />
<div className="h-2 w-full overflow-hidden rounded-full bg-foreground/15">
<div
className="h-full rounded-full bg-primary"
style={{ width: `${DEMO_CAMPAIGN.pct}%` }}
/>
</div>
<div className="flex justify-between text-xs text-muted-foreground">
<span>0.45 BTC</span>
<span>67%</span>
<div className="flex items-baseline justify-between gap-2 text-sm">
<span className="font-semibold">{DEMO_CAMPAIGN.raisedLabel}</span>
<span className="text-muted-foreground">of {DEMO_CAMPAIGN.goalLabel} goal</span>
</div>
</div>
{/* Organizer footer — mirrors CampaignCard's AuthorByline row. */}
<div className="flex items-center gap-2 border-t border-border/60 pt-3 text-xs text-muted-foreground">
<Avatar className="size-5">
<AvatarFallback className="bg-secondary text-[9px] text-secondary-foreground">
{DEMO_CAMPAIGN.organizer.slice(0, 1).toUpperCase()}
</AvatarFallback>
</Avatar>
<span className="truncate font-medium text-foreground/80">
{DEMO_CAMPAIGN.organizer}
</span>
</div>
</div>
</div>
+1 -4
View File
@@ -1107,10 +1107,7 @@
"confirm": { "title": "أكِّد وانتهيت", "body": "أقرّ بأن الحملة أصلية. تنضم شارتك إلى البطاقة ليعلم المتبرعون أنك تقف خلفها." }
},
"demo": {
"campaignTitle": "مياه نظيفة لموانزا",
"campaignOrganizer": "بواسطة مؤسسة Mradi",
"menuVerify": "وثّق هذه الحملة",
"verifiedBadge": "موثّقة بواسطتك"
"menuVerify": "وثّق هذه الحملة"
}
}
},
+1 -4
View File
@@ -1620,10 +1620,7 @@
}
},
"demo": {
"campaignTitle": "Clean Water for Mwanza",
"campaignOrganizer": "by Mradi Foundation",
"menuVerify": "Verify this campaign",
"verifiedBadge": "Verified by you"
"menuVerify": "Verify this campaign"
}
}
},
+1 -4
View File
@@ -1126,10 +1126,7 @@
}
},
"demo": {
"campaignTitle": "Agua limpia para Mwanza",
"campaignOrganizer": "de la Fundación Mradi",
"menuVerify": "Verificar esta campaña",
"verifiedBadge": "Verificada por ti"
"menuVerify": "Verificar esta campaña"
}
}
},
+1 -4
View File
@@ -1117,10 +1117,7 @@
"confirm": { "title": "تأیید کنید و کار تمام است", "body": "گواهی دهید که کمپین معتبر است. نشان شما به کارت افزوده می‌شود تا اهداکنندگان بدانند که شما پشتیبان آن هستید." }
},
"demo": {
"campaignTitle": "آب پاکیزه برای Mwanza",
"campaignOrganizer": "توسط بنیاد Mradi",
"menuVerify": "این کمپین را تأیید کنید",
"verifiedBadge": "تأییدشده توسط شما"
"menuVerify": "این کمپین را تأیید کنید"
}
}
},
+1 -4
View File
@@ -1565,10 +1565,7 @@
}
},
"demo": {
"campaignTitle": "De l'eau potable pour Mwanza",
"campaignOrganizer": "par la Fondation Mradi",
"menuVerify": "Vérifier cette campagne",
"verifiedBadge": "Vérifié par vous"
"menuVerify": "Vérifier cette campagne"
}
}
},
+1 -4
View File
@@ -1559,10 +1559,7 @@
"confirm": { "title": "पुष्टि करें और हो गया", "body": "प्रमाणित करें कि अभियान प्रामाणिक है। आपका बैज कार्ड में जुड़ जाता है ताकि दानदाताओं को पता चले कि आप इसके पीछे खड़े हैं।" }
},
"demo": {
"campaignTitle": "Mwanza के लिए स्वच्छ जल",
"campaignOrganizer": "Mradi Foundation द्वारा",
"menuVerify": "इस अभियान को सत्यापित करें",
"verifiedBadge": "आपके द्वारा सत्यापित"
"menuVerify": "इस अभियान को सत्यापित करें"
}
}
},
+1 -4
View File
@@ -1559,10 +1559,7 @@
"confirm": { "title": "Konfirmasi & selesai", "body": "Tegaskan bahwa kampanye ini autentik. Lencana Anda akan muncul di kartu sehingga para donatur tahu Anda mendukungnya." }
},
"demo": {
"campaignTitle": "Air Bersih untuk Mwanza",
"campaignOrganizer": "oleh Mradi Foundation",
"menuVerify": "Verifikasi kampanye ini",
"verifiedBadge": "Diverifikasi oleh Anda"
"menuVerify": "Verifikasi kampanye ini"
}
}
},
+1 -4
View File
@@ -1117,10 +1117,7 @@
"confirm": { "title": "បញ្ជាក់ ហើយអ្នកបានបញ្ចប់", "body": "បញ្ជាក់ថាយុទ្ធនាការនេះពិតប្រាកដ។ ផ្លាកសញ្ញារបស់អ្នកនឹងភ្ជាប់ទៅកាត ដើម្បីឱ្យអ្នកបរិច្ចាគដឹងថាអ្នកគាំទ្រវា។" }
},
"demo": {
"campaignTitle": "ទឹកស្អាតសម្រាប់ Mwanza",
"campaignOrganizer": "ដោយ Mradi Foundation",
"menuVerify": "ផ្ទៀងផ្ទាត់យុទ្ធនាការនេះ",
"verifiedBadge": "បានផ្ទៀងផ្ទាត់ដោយអ្នក"
"menuVerify": "ផ្ទៀងផ្ទាត់យុទ្ធនាការនេះ"
}
}
},
+1 -4
View File
@@ -1119,10 +1119,7 @@
"confirm": { "title": "تایید کړئ او کار مو پای ته ورسېد", "body": "تصدیق کړئ چې کمپاین اصلي دی. ستاسو نښان د کارت سره یوځای کېږي ترڅو بسپنه ورکوونکي پوه شي چې تاسو یې ملاتړ کوئ." }
},
"demo": {
"campaignTitle": "د موانزا لپاره پاکې اوبه",
"campaignOrganizer": "د Mradi بنسټ لخوا",
"menuVerify": "دا کمپاین تصدیق کړئ",
"verifiedBadge": "ستاسو لخوا تصدیق شوی"
"menuVerify": "دا کمپاین تصدیق کړئ"
}
}
},
+1 -4
View File
@@ -1570,10 +1570,7 @@
}
},
"demo": {
"campaignTitle": "Água Limpa para Mwanza",
"campaignOrganizer": "por Mradi Foundation",
"menuVerify": "Verificar esta campanha",
"verifiedBadge": "Verificado por você"
"menuVerify": "Verificar esta campanha"
}
}
},
+1 -4
View File
@@ -1570,10 +1570,7 @@
}
},
"demo": {
"campaignTitle": "Чистая вода для Mwanza",
"campaignOrganizer": "от Mradi Foundation",
"menuVerify": "Проверить эту кампанию",
"verifiedBadge": "Проверено вами"
"menuVerify": "Проверить эту кампанию"
}
}
},
+1 -4
View File
@@ -1119,10 +1119,7 @@
"confirm": { "title": "Simbisa uye wapedza", "body": "Pupura kuti mushandirapamwe ndewechokwadi. Bheji rako rinobatana nekadhi kuti vanopa vazive kuti unowutsigira." }
},
"demo": {
"campaignTitle": "Mvura Yakachena yeMwanza",
"campaignOrganizer": "naMradi Foundation",
"menuVerify": "Simbisa mushandirapamwe uyu",
"verifiedBadge": "Yasimbiswa newe"
"menuVerify": "Simbisa mushandirapamwe uyu"
}
}
},
+1 -4
View File
@@ -1558,10 +1558,7 @@
"confirm": { "title": "Thibitisha na umemaliza", "body": "Shuhudia kuwa kampeni ni halisi. Beji yako huungana na kadi ili wafadhili wajue unaiunga mkono." }
},
"demo": {
"campaignTitle": "Maji Safi kwa Mwanza",
"campaignOrganizer": "na Mradi Foundation",
"menuVerify": "Thibitisha kampeni hii",
"verifiedBadge": "Imethibitishwa na wewe"
"menuVerify": "Thibitisha kampeni hii"
}
}
},
+1 -4
View File
@@ -1560,10 +1560,7 @@
"confirm": { "title": "Onaylayın ve işlem tamam", "body": "Kampanyanın gerçek olduğunu teyit edin. Rozetiniz kartta yerini alır, böylece bağışçılar arkasında durduğunuzu bilir." }
},
"demo": {
"campaignTitle": "Mwanza için Temiz Su",
"campaignOrganizer": "Mradi Vakfı tarafından",
"menuVerify": "Bu kampanyayı doğrula",
"verifiedBadge": "Sizin tarafınızdan doğrulandı"
"menuVerify": "Bu kampanyayı doğrula"
}
}
},
+1 -4
View File
@@ -1119,10 +1119,7 @@
"confirm": { "title": "確認後即完成", "body": "證明這個專案是真實的。你的徽章會加入卡片,讓捐款者知道你為它背書。" }
},
"demo": {
"campaignTitle": "為姆萬扎提供潔淨用水",
"campaignOrganizer": "由 Mradi 基金會發起",
"menuVerify": "驗證此活動",
"verifiedBadge": "已由你驗證"
"menuVerify": "驗證此活動"
}
}
},
+1 -4
View File
@@ -1119,10 +1119,7 @@
"confirm": { "title": "确认即可完成", "body": "证明该活动真实可信。你的徽章会出现在卡片上,让捐赠者知道你为它背书。" }
},
"demo": {
"campaignTitle": "为 Mwanza 提供清洁饮水",
"campaignOrganizer": "由 Mradi 基金会发起",
"menuVerify": "验证此活动",
"verifiedBadge": "已由你验证"
"menuVerify": "验证此活动"
}
}
},