97 lines
3.6 KiB
TypeScript
97 lines
3.6 KiB
TypeScript
/*
|
|
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 <https://www.gnu.org/licenses/>.
|
|
|
|
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<number>()
|
|
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 (
|
|
<ConfirmDialog
|
|
open={
|
|
!!profile &&
|
|
hasMigratedToken === true &&
|
|
!parseUserSettings(profile.setting).astra_cost_notice_ack &&
|
|
dismissedUserId !== userId
|
|
}
|
|
onOpenChange={(value) => {
|
|
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()}
|
|
/>
|
|
)
|
|
}
|