import { useEffect, useState } from 'react' import { useQueryClient } from '@tanstack/react-query' import { Loader2, RefreshCw, DollarSign } from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { formatCurrencyFromUSD } from '@/lib/currency' import { formatTimestampToDate } from '@/lib/format' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { getCodexUsage, updateChannelBalance } from '../../api' import { channelsQueryKeys } from '../../lib' import { useChannels } from '../channels-provider' import { CodexUsageDialog, type CodexUsageDialogData, } from './codex-usage-dialog' type BalanceQueryDialogProps = { open: boolean onOpenChange: (open: boolean) => void } export function BalanceQueryDialog({ open, onOpenChange, }: BalanceQueryDialogProps) { const { t } = useTranslation() const { currentRow, setCurrentRow } = useChannels() const queryClient = useQueryClient() const [isQuerying, setIsQuerying] = useState(false) const [balance, setBalance] = useState(null) const [balanceUpdatedTime, setBalanceUpdatedTime] = useState( null ) const [codexUsageResponse, setCodexUsageResponse] = useState(null) const isCodex = currentRow?.type === 57 const handleQueryCodexUsage = async () => { const row = currentRow if (!row) return setIsQuerying(true) try { const res = await getCodexUsage(row.id) if (!res.success) { throw new Error(res.message || t('Failed to fetch usage')) } setCodexUsageResponse(res) } catch (error: unknown) { toast.error( error instanceof Error ? error.message : t('Failed to fetch usage') ) } finally { setIsQuerying(false) } } useEffect(() => { if (!isCodex) return if (!open) return handleQueryCodexUsage() // eslint-disable-next-line react-hooks/exhaustive-deps }, [open, isCodex]) if (!currentRow) return null const handleQueryBalance = async () => { setIsQuerying(true) try { const response = await updateChannelBalance(currentRow.id) if (response.success && response.balance !== undefined) { const newBalance = response.balance const now = Math.floor(Date.now() / 1000) setBalance(newBalance) setBalanceUpdatedTime(now) toast.success(t('Balance updated successfully')) // Update currentRow immediately with new balance and timestamp setCurrentRow({ ...currentRow, balance: newBalance, balance_updated_time: now, }) // Invalidate queries to refresh the table await queryClient.invalidateQueries({ queryKey: channelsQueryKeys.lists(), }) } else { toast.error(response.message || t('Failed to query balance')) } } catch (error: unknown) { toast.error( error instanceof Error ? error.message : t('Failed to query balance') ) } finally { setIsQuerying(false) } } const handleClose = () => { setBalance(null) setBalanceUpdatedTime(null) setCodexUsageResponse(null) onOpenChange(false) } const formatBalance = (bal: number) => formatCurrencyFromUSD(bal, { digitsLarge: 2, digitsSmall: 4, abbreviate: false, }) const formatDate = (timestamp: number) => { if (!timestamp) return 'Never' return formatTimestampToDate(timestamp) } if (isCodex) { return ( { if (!v) handleClose() }} channelName={currentRow.name} channelId={currentRow.id} response={codexUsageResponse} onRefresh={handleQueryCodexUsage} isRefreshing={isQuerying} /> ) } return ( {t('Query Balance')} {t('Update balance for:')} {currentRow.name}
{/* Current Balance Display */}
{t('Current Balance')}
{balance !== null ? formatBalance(balance) : formatBalance(currentRow.balance)}
{t('Last updated:')}{' '} {formatDate( balanceUpdatedTime ?? currentRow.balance_updated_time )}
{/* Balance Update Button */}
) }