/* 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 type { ChangeEvent } from 'react' import * as z from 'zod' import type { Resolver } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { useTranslation } from 'react-i18next' import { Alert, AlertDescription } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form' import { Input } from '@/components/ui/input' import { Switch } from '@/components/ui/switch' import { FormDirtyIndicator } from '../components/form-dirty-indicator' import { FormNavigationGuard } from '../components/form-navigation-guard' import { SettingsSection } from '../components/settings-section' import { useSettingsForm } from '../hooks/use-settings-form' import { useUpdateOption } from '../hooks/use-update-option' const quotaSchema = z.object({ QuotaForNewUser: z.coerce.number().min(0), PreConsumedQuota: z.coerce.number().min(0), QuotaForInviter: z.coerce.number().min(0), QuotaForInvitee: z.coerce.number().min(0), TopUpLink: z.string(), general_setting: z.object({ docs_link: z.string(), }), quota_setting: z.object({ enable_free_model_pre_consume: z.boolean(), }), }) type QuotaFormValues = z.infer type QuotaSettingsSectionProps = { defaultValues: QuotaFormValues complianceConfirmed?: boolean } export function QuotaSettingsSection({ defaultValues, complianceConfirmed = true, }: QuotaSettingsSectionProps) { const { t } = useTranslation() const updateOption = useUpdateOption() const handleNumberChange = (onChange: (value: number | string) => void) => (event: ChangeEvent) => { onChange( event.target.value === '' ? '' : event.currentTarget.valueAsNumber ) } const { form, handleSubmit, isDirty, isSubmitting } = useSettingsForm({ resolver: zodResolver(quotaSchema) as Resolver< QuotaFormValues, unknown, QuotaFormValues >, defaultValues, onSubmit: async (_data, changedFields) => { for (const [key, value] of Object.entries(changedFields)) { await updateOption.mutateAsync({ key, value: value as string | number | boolean, }) } }, }) return ( {!complianceConfirmed ? ( {t( 'Non-zero invitation rewards require compliance confirmation in Payment Gateway settings.' )} ) : null}
( {t('New User Quota')} {t('Initial quota given to new users')} )} /> ( {t('Pre-Consumed Quota')} {t('Quota consumed before charging users')} )} /> ( {t('Inviter Reward')} {t('Quota given to users who invite others')} )} /> ( {t('Invitee Reward')} {t('Quota given to invited users')} )} /> (
{t('Pre-Consume for Free Models')} {t( 'When enabled, zero-cost models also pre-consume quota before final settlement.' )}
)} /> ( {t('Top-Up Link')} {t('External link for users to purchase quota')} )} /> ( {t('Documentation Link')} {t('Link to your documentation site')} )} />
) }