feat(sasquatch): show the owner AI balance on the panel header
Owner-only chip (next to the Pro/CVM chips) showing the upstream sats balance, amber when low. useSasquatchAiStatus gains an 'enabled' option; the panel only fetches while it is open, so the NIP-98 signature never fires at app startup.
This commit is contained in:
parent
69e1ae17b8
commit
821522327c
3 changed files with 22 additions and 2 deletions
|
|
@ -142,6 +142,8 @@ session with **no other memory of this project**. So:
|
|||
Owner Settings shows the upstream balance (`SasquatchAiStatusCard`) via the
|
||||
owner-only `POST /api/ai/status` (NIP-98 + owner pubkey → `handleStatus`), with
|
||||
a "low balance" warning below 500 sats — the top-up nudge (no webhook needed).
|
||||
The same balance shows as a chip in the Sasquatch panel header (owner-only,
|
||||
fetched only while the panel is open so it never prompts at startup).
|
||||
**AI answers are Pro-only**: free users get the static FAQ/glossary + local
|
||||
relay lookups only (`if (isPro)` gates the AI block in `SasquatchGuide`).
|
||||
Pro access (`useSasquatchPro`) is granted by a provider-authored zap receipt,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import { useCurrentUser } from '@/hooks/useCurrentUser';
|
|||
import { useCVMClient } from '@/hooks/useCVMClient';
|
||||
import { usePersonalContext } from '@/hooks/usePersonalContext';
|
||||
import { useSasquatchPro } from '@/hooks/useSasquatchPro';
|
||||
import { useSasquatchAiStatus } from '@/hooks/useSasquatchAiStatus';
|
||||
import { PLATFORM_OWNER_PUBKEYS } from '@/hooks/useListingRestrictions';
|
||||
import { SasquatchProDialog } from '@/components/SasquatchProDialog';
|
||||
import { useSasquatchActions, type SasquatchDraft } from '@/hooks/useSasquatchActions';
|
||||
import { SasquatchActionCard } from '@/components/SasquatchActionCard';
|
||||
|
|
@ -636,11 +638,16 @@ export function SasquatchGuide({ message, onDismiss }: SasquatchGuideProps) {
|
|||
const cvm = useCVMClient();
|
||||
const personal = usePersonalContext();
|
||||
const { isPro, receiptEvent } = useSasquatchPro();
|
||||
// Owner-only: show the AI (Routstr) balance on the panel — fetched only while
|
||||
// the panel is open, so it never prompts at startup.
|
||||
const isOwner = !!user?.pubkey && PLATFORM_OWNER_PUBKEYS.includes(user.pubkey);
|
||||
const { publishDraft } = useSasquatchActions();
|
||||
const [proDialogOpen, setProDialogOpen] = useState(false);
|
||||
|
||||
const [isMinimized, setIsMinimized] = useLocalStorage('sasquatch-minimized', false);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
// Fetched only while the panel is open (owner-only).
|
||||
const aiStatus = useSasquatchAiStatus({ enabled: isOwner && isVisible && !isMinimized });
|
||||
const [chatMessages, setChatMessages] = useState<ChatMessage[]>([]);
|
||||
const [userInput, setUserInput] = useState('');
|
||||
const [showChat, setShowChat] = useState(false);
|
||||
|
|
@ -1547,6 +1554,17 @@ Instructions:
|
|||
</button>
|
||||
) : null}
|
||||
<CVMStatus connected={cvmConnected} />
|
||||
{isOwner && aiStatus.data?.configured && aiStatus.data.balanceSats != null && (
|
||||
<span
|
||||
className={cn(
|
||||
'flex items-center gap-0.5 rounded px-1 py-0.5 text-[8px] font-black uppercase tracking-wider',
|
||||
aiStatus.data.low ? 'bg-amber-500/20 text-amber-400' : 'bg-emerald-500/15 text-emerald-400',
|
||||
)}
|
||||
title={`Sasquatch AI balance — top up at ${aiStatus.data.provider ?? 'the node'}`}
|
||||
>
|
||||
⚡ {aiStatus.data.balanceSats.toLocaleString()} sats
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-[10px] text-[#ccff00]/50 leading-none mt-0.5">
|
||||
{activeMessage.title}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ const AI_STATUS_URL = Capacitor.isNativePlatform()
|
|||
* nudged to top up before AI silently degrades to the keyless fallback. Polled
|
||||
* every few minutes. Returns `undefined`/skips for non-owners.
|
||||
*/
|
||||
export function useSasquatchAiStatus() {
|
||||
export function useSasquatchAiStatus(options: { enabled?: boolean } = {}) {
|
||||
const { user } = useCurrentUser();
|
||||
const isOwner = !!user?.pubkey && PLATFORM_OWNER_PUBKEYS.includes(user.pubkey);
|
||||
|
||||
return useQuery<SasquatchAiStatus>({
|
||||
queryKey: ['sasquatch-ai-status', user?.pubkey],
|
||||
enabled: isOwner,
|
||||
enabled: (options.enabled ?? true) && isOwner,
|
||||
refetchInterval: 5 * 60 * 1000,
|
||||
staleTime: 60 * 1000,
|
||||
queryFn: async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue