SkateSpots/src/components/SasquatchAiStatusCard.tsx
SkateSpots 3e6354995a i18n(es): batch 3 part 1 — routing UI, Sasquatch panel, collections, splash
- routeUi.* (123 keys): RouteDialog (incl. follow-mode banner, transit time
  picker + mode filters, itinerary legs), StopDepartures, TripItineraryCard.
- sasquatchUi.* (81 keys): SasquatchGuide, SasquatchProDialog,
  SasquatchActionCard, SasquatchAiStatusCard. LLM prompts + chat bodies
  deliberately left English.
- collectionUi.* / bootUi.*: AddToCollectionDialog example placeholders,
  SplashScreen rotating status lines + aria labels.
- New src/i18n/batch3/* fragment files, spread into en/es so parallel passes
  never edit the big literal.
2026-10-02 15:15:06 +07:00

65 lines
2.6 KiB
TypeScript

import { AlertTriangle, Coins, Loader2 } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { PLATFORM_OWNER_PUBKEYS } from '@/hooks/useListingRestrictions';
import { useSasquatchAiStatus } from '@/hooks/useSasquatchAiStatus';
import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
/**
* Owner-only card: the Sasquatch AI (Routstr node) balance, with a warning when
* it's running low. This is the "top up before AI degrades" nudge — no webhook
* needed, since the operator can see it live in Settings.
*/
export function SasquatchAiStatusCard() {
const { t } = useTranslation();
const { user } = useCurrentUser();
const isOwner = !!user?.pubkey && PLATFORM_OWNER_PUBKEYS.includes(user.pubkey);
const { data, isLoading, isError } = useSasquatchAiStatus();
if (!isOwner) return null;
const low = data?.low === true;
const balance = data?.balanceSats;
return (
<Card className={cn('overflow-hidden bg-white/2', low ? 'border-amber-500/40' : 'border-white/10')}>
<CardContent className="py-3.5">
<div className="flex items-center justify-between gap-3">
<p className="flex items-center gap-2 text-sm font-bold text-white">
{low ? (
<AlertTriangle className="h-4 w-4 text-amber-400" />
) : (
<Coins className="h-4 w-4 text-red-400" />
)}
{t('sasquatchUi.aiTitle')}
<span className="rounded bg-red-500/10 px-1.5 py-0.5 text-[9px] font-black uppercase tracking-widest text-red-400/70">
{t('sasquatchUi.owner')}
</span>
</p>
<span
className={cn(
'shrink-0 text-xs font-bold',
isError ? 'text-gray-500' : low ? 'text-amber-400' : 'text-green-400',
)}
>
{isLoading ? (
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
) : isError || data?.configured === false ? (
t('sasquatchUi.notConfigured')
) : balance === null || balance === undefined ? (
t('sasquatchUi.unavailable')
) : (
t('sasquatchUi.satsValue', { balance: balance.toLocaleString() })
)}
</span>
</div>
<p className="mt-1 text-xs text-muted-foreground">
{low
? t('sasquatchUi.lowBalance', { provider: data?.provider ?? t('sasquatchUi.theNode') })
: t('sasquatchUi.aiDesc')}
</p>
</CardContent>
</Card>
);
}