SkateSpots/src/components/EscrowPanel.tsx
SkateSpots 09735375c2 feat(i18n): Spanish (Castellano) — infra + Map/Spots, Marketplace, Lab (batch 1)
- First-visit language auto-detect (Spanish devices land in es; stored choice wins).
- Sasquatch AI replies in the app language (skate trick names kept English).
- i18n safety net: scripts/check-i18n.mjs wired into npm test — fails on any t()
  key missing from en/es or any en/es key drift.
- ~1,680 new keys (2,297 total) across mapUi / spotUi / marketUi / labUi and
  ~65 files wired to t(): Map, spots (detail/create/edit/chat), marketplace,
  trades, offers, escrow, shipping, The Lab, /become/* forms, coaches, skaters.
- Policy: only skate TRICK names stay English; user-generated content untouched.
2026-10-01 23:57:20 +07:00

74 lines
2.2 KiB
TypeScript

import { useMemo } from 'react';
import { Lock } from 'lucide-react';
import { parseEscrowToken, type EscrowTokenInfo } from '@/lib/cashuEscrow';
import { cn } from '@/lib/utils';
import { useTranslation } from '@/contexts/language';
function hostOf(url: string): string {
try {
return new URL(url).host;
} catch {
return url;
}
}
function formatDate(seconds: number): string {
return new Date(seconds * 1000).toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
});
}
/**
* Read-only escrow summary for a locked Cashu token. Pure/offline (uses
* `parseEscrowToken`), so it renders on web as well as native — only the
* mint-touching create/redeem actions are native-only.
*/
export function EscrowPanel({ token, className }: { token: string; className?: string }) {
const { t } = useTranslation();
const info = useMemo<EscrowTokenInfo | null>(() => {
try {
return parseEscrowToken(token);
} catch {
return null;
}
}, [token]);
if (!info || !info.locked) return null;
const locktime = info.policy?.locktime;
return (
<div
className={cn(
'rounded-xl border border-[#ff6600]/30 bg-[#ff6600]/5 p-3 text-xs',
className,
)}
>
<div className="flex items-center gap-2 font-bold text-[#ff6600]">
<Lock className="h-3.5 w-3.5" />
{t('marketUi.escrowPanel.escrowed', { amount: info.amount.toLocaleString() })}
</div>
<div className="mt-1 space-y-0.5 text-gray-400">
<p>
{t('marketUi.escrowPanel.mint')}: <span className="text-gray-300">{hostOf(info.mint)}</span>
</p>
{locktime ? (
<p>
{info.refundable ? (
<>{t('marketUi.escrowPanel.refundSinceBefore')}{' '}
<span className="text-[#ccff00]">{formatDate(locktime)}</span>
</>
) : (
<>{t('marketUi.escrowPanel.redeemBefore')}{' '}
<span className="text-gray-300">{formatDate(locktime)}</span>
</>
)}
</p>
) : (
<p>{t('marketUi.escrowPanel.noExpiry')}</p>
)}
</div>
</div>
);
}