/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { ConfirmDialog } from '@/components/confirm-dialog' import { getUserProfile, updateUserSettings } from '@/features/profile/api' import { parseUserSettings } from '@/features/profile/lib/format' import { handleServerError } from '@/lib/handle-server-error' import { requireServerSuccess } from '@/lib/server-error-message' import { useAuthStore } from '@/stores/auth-store' import { getApiKeys } from '../api' export function AstraCostNotice() { const { t } = useTranslation() const userId = useAuthStore((state) => state.auth.user?.id) const queryClient = useQueryClient() const [dismissedUserId, setDismissedUserId] = useState() const noticeKey = ['astra-cost-notice', userId] const { data: profile } = useQuery({ queryKey: noticeKey, queryFn: async () => requireServerSuccess(await getUserProfile()).data, enabled: userId !== undefined, }) const { data: hasMigratedToken } = useQuery({ queryKey: ['astra-cost-notice-tokens', userId], queryFn: async () => { let page = 1 for (;;) { const result = await getApiKeys({ p: page, size: 100 }) if (!result.success || !result.data) { throw new Error(result.message || t('Failed to load API keys')) } if ( result.data.items.some((token) => token.astra_auto_switch === true) ) { return true } if (page * result.data.page_size >= result.data.total) return false page += 1 } }, enabled: userId !== undefined, }) const acknowledge = useMutation({ mutationFn: async () => requireServerSuccess( await updateUserSettings({ astra_cost_notice_ack: true }) ), onSuccess: () => { setDismissedUserId(userId) void queryClient.invalidateQueries({ queryKey: noticeKey }) }, onError: (error) => handleServerError(error, t('Failed to update settings')), }) return ( { if (!value && !acknowledge.isPending) setDismissedUserId(userId) }} title={t('Astra auto-switch and charges')} desc={t( 'Existing API keys keep Astra auto-switch enabled; new keys default to off. Rejected results still incur usage charges, and every additional upstream attempt is charged separately. You can change this setting for each API key.' )} cancelBtnText={t('Remind me next time')} confirmText={t('I understand')} isLoading={acknowledge.isPending} handleConfirm={() => acknowledge.mutate()} /> ) }