- H13 offer threads: the seller is ALWAYS the listing author (derived from the event pubkey), never a self-declared role tag — a non-owner can no longer appear as the seller with a payment pointer. - H12 trade reputation: a preimage/deposit proof counts at most once, so a real payment can't be reused across attestations to inflate payment-verified. - Crew alerts: listed crews are filtered against the user's own membership confirmation labels (one batched query), so a confirmed member no longer gets a phantom 'confirm to join' badge/notification when the crew is edited. - Error boundaries (app + route) and DesktopNavManager are translated; the class boundary renders a translated functional ErrorFallback. New batch4 namespaces errorsUi.* / desktopNav.*.
79 lines
2.8 KiB
TypeScript
79 lines
2.8 KiB
TypeScript
import { useTranslation } from '@/contexts/language';
|
|
|
|
/**
|
|
* Translated error-boundary UI. A FUNCTION component so it can use `t()` — the
|
|
* class ErrorBoundary renders it, which keeps the class (React error boundaries
|
|
* must be classes) while making the copy language-aware.
|
|
*/
|
|
export function ErrorFallback({
|
|
variant,
|
|
onReset,
|
|
onReload,
|
|
onBack,
|
|
}: {
|
|
variant: 'app' | 'route';
|
|
onReset?: () => void;
|
|
onReload: () => void;
|
|
onBack?: () => void;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const isApp = variant === 'app';
|
|
|
|
return (
|
|
<div
|
|
className={
|
|
isApp
|
|
? 'min-h-screen bg-black text-white flex items-center justify-center p-4'
|
|
: 'min-h-[60vh] flex items-center justify-center p-6'
|
|
}
|
|
>
|
|
<div className={isApp ? 'max-w-md w-full space-y-6 text-center' : 'max-w-sm w-full text-center space-y-5'}>
|
|
<div
|
|
className={
|
|
isApp
|
|
? 'mx-auto flex h-16 w-16 items-center justify-center rounded-2xl bg-[#ff0040]/15 border border-[#ff0040]/30 text-4xl'
|
|
: 'mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-[#ff0040]/15 border border-[#ff0040]/30 text-3xl'
|
|
}
|
|
>
|
|
🛹
|
|
</div>
|
|
<div className={isApp ? 'space-y-2' : 'space-y-1.5'}>
|
|
<h2 className={isApp ? 'text-2xl font-black uppercase text-[#ff0040]' : 'text-xl font-black uppercase text-[#ff0040]'}>
|
|
{isApp ? t('errorsUi.slammedTitle') : t('errorsUi.pageSlammedTitle')}
|
|
</h2>
|
|
<p className={isApp ? 'text-gray-400' : 'text-sm text-gray-400'}>
|
|
{isApp ? t('errorsUi.slammedBody') : t('errorsUi.pageSlammedBody')}
|
|
</p>
|
|
</div>
|
|
<div className="flex flex-col sm:flex-row gap-2">
|
|
{onReset && (
|
|
<button
|
|
onClick={onReset}
|
|
className="flex-1 px-4 py-3 rounded-full font-black uppercase bg-[#ff0040] text-white hover:bg-[#ff0040]/90 transition-colors"
|
|
>
|
|
{t('errorsUi.tryAgain')}
|
|
</button>
|
|
)}
|
|
<button
|
|
onClick={onReload}
|
|
className={
|
|
isApp
|
|
? 'flex-1 px-4 py-3 rounded-full font-bold border border-white/20 text-white hover:bg-white/5 transition-colors'
|
|
: 'flex-1 px-4 py-3 rounded-full font-black uppercase bg-[#ff0040] text-white hover:bg-[#ff0040]/90 transition-colors'
|
|
}
|
|
>
|
|
{isApp ? t('errorsUi.reloadApp') : t('errorsUi.reload')}
|
|
</button>
|
|
{onBack && (
|
|
<button
|
|
onClick={onBack}
|
|
className="flex-1 px-4 py-3 rounded-full font-black uppercase bg-white/5 text-gray-300 border border-white/10 hover:bg-white/10 transition-colors"
|
|
>
|
|
{t('errorsUi.goBack')}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|