- New src/lib/dateFnsI18n.ts re-exports date-fns with formatDistanceToNow /
formatDistanceToNowStrict / formatDistance / format defaulting to the active
locale, plus dateLocaleCode() for native toLocale{Date,Time}String calls.
- LanguageProvider keeps the locale in sync during render, so the first paint is
already in-language.
- Codemod: 11 date-fns imports now use the shim; ~39 native date/time calls pass
the app locale code instead of undefined/[]/hardcoded 'en-US'. Number
.toLocaleString() calls are deliberately untouched.
75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { dateLocaleCode } from '@/lib/dateFnsI18n';
|
|
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(dateLocaleCode(), {
|
|
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>
|
|
);
|
|
}
|