import { getNodeGroupList, getNodeList } from '@/services/admin/server'; import { getSubscribeGroupList } from '@/services/admin/subscribe'; import { Icon } from '@iconify/react'; import { Combobox } from '@repo/ui/combobox'; import { ArrayInput } from '@repo/ui/dynamic-Inputs'; import { JSONEditor } from '@repo/ui/editor'; import { EnhancedInput } from '@repo/ui/enhanced-input'; import { unitConversion } from '@repo/ui/utils'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@shadcn/ui/accordion'; import { Button } from '@shadcn/ui/button'; import { Checkbox } from '@shadcn/ui/checkbox'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@shadcn/ui/form'; import { Label } from '@shadcn/ui/label'; import { useForm } from '@shadcn/ui/lib/react-hook-form'; import { z, zodResolver } from '@shadcn/ui/lib/zod'; import { ScrollArea } from '@shadcn/ui/scroll-area'; import { Sheet, SheetContent, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, } from '@shadcn/ui/sheet'; import { useQuery } from '@tanstack/react-query'; import { useTranslations } from 'next-intl'; import { useTheme } from 'next-themes'; import { assign, shake } from 'radash'; import { useEffect, useState } from 'react'; interface SubscribeFormProps { onSubmit: (data: T) => Promise | boolean; initialValues?: T; loading?: boolean; trigger: string; title: string; } const defaultValues = { inventory: -1, speed_limit: 0, device_limit: 0, traffic: 0, quota: 0, discount: [], server_group: [], server: [], }; export default function SubscribeForm>({ onSubmit, initialValues, loading, trigger, title, }: SubscribeFormProps) { const t = useTranslations('subscribe'); const { resolvedTheme } = useTheme(); const [open, setOpen] = useState(false); const formSchema = z.object({ name: z.string(), description: z.string().optional(), unit_price: z.number(), replacement: z.number().optional(), discount: z .array( z.object({ months: z.number(), discount: z.number(), }), ) .optional(), inventory: z.number().optional(), speed_limit: z.number().optional(), device_limit: z.number().optional(), traffic: z.number().optional(), quota: z.number().optional(), group_id: z.number().optional().nullish(), server_group: z.array(z.number()).optional(), server: z.array(z.number()).optional(), }); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: assign( defaultValues, shake(initialValues, (value) => value === null) as Record, ), }); useEffect(() => { form?.reset( assign(defaultValues, shake(initialValues, (value) => value === null) as Record), ); }, [form, initialValues]); async function handleSubmit(data: { [x: string]: any }) { const bool = await onSubmit(data as T); if (bool) setOpen(false); } const { data: group } = useQuery({ queryKey: ['getSubscribeGroupList'], queryFn: async () => { const { data } = await getSubscribeGroupList(); return data.data?.list as API.SubscribeGroup[]; }, }); const { data: server } = useQuery({ queryKey: ['getNodeList', 'all'], queryFn: async () => { const { data } = await getNodeList({ page: 1, size: 9999, }); return data.data?.list; }, }); const { data: server_groups } = useQuery({ queryKey: ['getNodeGroupList'], queryFn: async () => { const { data } = await getNodeGroupList(); return (data.data?.list || []) as API.ServerGroup[]; }, }); return ( {title}
( {t('form.name')} { form.setValue(field.name, value); }} /> )} /> ( { form.setValue(field.name, value); }} placeholder={{ description: 'description', features: [ { type: 'default', icon: '', label: 'label', }, ], }} schema={{ type: 'object', properties: { description: { type: 'string', description: 'A brief description of the item.', }, features: { type: 'array', items: { type: 'object', properties: { icon: { type: 'string', description: "Enter an Iconify icon identifier (e.g., 'mdi:account').", pattern: '^[a-z0-9]+:[a-z0-9-]+$', examples: [ 'uil:shield-check', 'uil:shield-exclamation', 'uil:database', 'uil:server', 'Visit https://icon-sets.iconify.design to browse available icons.', ], }, label: { type: 'string', description: 'The label describing the feature.', }, type: { type: 'string', enum: ['default', 'success', 'destructive'], description: 'The type of feature, limited to specific values.', }, }, }, description: 'A list of feature objects.', }, }, required: ['description', 'features'], additionalProperties: false, }} /> )} />
( {t('form.unit_price')} unitConversion('centsToDollars', value)} formatOutput={(value) => unitConversion('dollarsToCents', value)} onValueChange={(value) => { form.setValue(field.name, value); }} /> )} /> ( {t('form.replacement')} unitConversion('centsToDollars', value)} formatOutput={(value) => unitConversion('dollarsToCents', value)} onValueChange={(value) => { form.setValue(field.name, value); }} /> )} /> ( {t('form.traffic')} unitConversion('bytesToGb', value)} formatOutput={(value) => unitConversion('gbToBytes', value)} suffix='GB' onValueChange={(value) => { form.setValue(field.name, value); }} /> )} /> ( {t('form.speedLimit')} unitConversion('bitsToMb', value)} formatOutput={(value) => unitConversion('mbToBits', value)} suffix='MB' onValueChange={(value) => { form.setValue(field.name, value); }} /> )} /> ( {t('form.deviceLimit')} { form.setValue(field.name, value); }} /> )} /> ( {t('form.inventory')} { form.setValue(field.name, value); }} /> )} /> ( {t('form.quota')} { form.setValue(field.name, value); }} /> )} /> ( {t('form.subscribeGroup')} placeholder={t('form.selectSubscribeGroup')} {...field} onChange={(value) => { form.setValue(field.name, value); }} options={group?.map((item) => ({ label: item.name, value: item.id, }))} /> )} />
( {t('form.discount')} fields={[ { name: 'months', type: 'number', min: 1, suffix: t('form.discountMonths'), }, { name: 'discount', type: 'number', min: 1, max: 100, placeholder: t('form.discountPercent'), suffix: '%', }, ]} value={field.value} onChange={(value) => { form.setValue(field.name, value); }} /> {t('form.discountDescription')} )} />
( {t('form.serverGroup')} {server_groups?.map((group: API.ServerGroup) => { const value = field.value || []; return (
{ return checked ? form.setValue(field.name, [...value, group.id]) : form.setValue( field.name, value.filter((value: number) => value !== group.id), ); }} />
    {server ?.filter((server: API.Server) => server.groupId === group.id) ?.map((node: API.Server) => { return (
  • {node.name} {node.server_addr} {node.protocol}
  • ); })}
); })}
)} /> ( {t('form.server')}
{server ?.filter((item: API.Server) => !item.groupId) ?.map((item: API.Server) => { const value = field.value || []; return (
{ return checked ? form.setValue(field.name, [...value, item.id]) : form.setValue( field.name, value.filter((value: number) => value !== item.id), ); }} />
); })}
)} />
); }