import { useEffect, useState } from 'react' import { useForm, type Resolver } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { CalendarClock, CreditCard, RefreshCw, Settings2 } from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from '@/components/ui/sheet' import { Switch } from '@/components/ui/switch' import { createPlan, updatePlan, getGroups } from '../api' import { getDurationUnitOptions, getResetPeriodOptions } from '../constants' import { getPlanFormSchema, PLAN_FORM_DEFAULTS, planToFormValues, formValuesToPlanPayload, type PlanFormValues, } from '../lib' import type { PlanRecord } from '../types' import { useSubscriptions } from './subscriptions-provider' interface Props { open: boolean onOpenChange: (open: boolean) => void currentRow?: PlanRecord } export function SubscriptionsMutateDrawer({ open, onOpenChange, currentRow, }: Props) { const { t } = useTranslation() const isEdit = !!currentRow?.plan?.id const { triggerRefresh } = useSubscriptions() const [isSubmitting, setIsSubmitting] = useState(false) const [groupOptions, setGroupOptions] = useState([]) const schema = getPlanFormSchema(t) const form = useForm({ resolver: zodResolver(schema) as unknown as Resolver, defaultValues: PLAN_FORM_DEFAULTS, }) useEffect(() => { if (open) { if (currentRow?.plan) { form.reset(planToFormValues(currentRow.plan)) } else { form.reset(PLAN_FORM_DEFAULTS) } getGroups() .then((res) => { if (res.success) setGroupOptions(res.data || []) }) .catch(() => {}) } }, [open, currentRow, form]) const durationUnit = form.watch('duration_unit') const resetPeriod = form.watch('quota_reset_period') const onSubmit = async (values: PlanFormValues) => { setIsSubmitting(true) try { const payload = formValuesToPlanPayload(values) if (isEdit && currentRow?.plan?.id) { const res = await updatePlan(currentRow.plan.id, payload) if (res.success) { toast.success(t('Update succeeded')) onOpenChange(false) triggerRefresh() } } else { const res = await createPlan(payload) if (res.success) { toast.success(t('Create succeeded')) onOpenChange(false) triggerRefresh() } } } catch { toast.error(t('Request failed')) } finally { setIsSubmitting(false) } } const durationUnitOpts = getDurationUnitOptions(t) const resetPeriodOpts = getResetPeriodOptions(t) return ( { onOpenChange(v) if (!v) { form.reset() } }} > {isEdit ? t('Update plan info') : t('Create new subscription plan')} {isEdit ? t('Modify existing subscription plan configuration') : t( 'Fill in the following info to create a new subscription plan' )}
{/* Basic Info */}

{t('Basic Info')}

( {t('Plan Title')} )} /> ( {t('Plan Subtitle')} )} />
( {t('Actual Amount')} field.onChange(parseFloat(e.target.value) || 0) } /> )} /> ( {t('Total Quota')} field.onChange(parseFloat(e.target.value) || 0) } /> {t('0 means unlimited')} )} />
( {t('Upgrade Group')} )} /> ( {t('Purchase Limit')} field.onChange(parseInt(e.target.value, 10) || 0) } /> {t('0 means unlimited')} )} />
( {t('Sort Order')} field.onChange(parseInt(e.target.value, 10) || 0) } /> )} /> ( {t('Enabled Status')} )} />
{/* Duration Settings */}

{t('Duration Settings')}

( {t('Duration Unit')} )} /> {durationUnit === 'custom' ? ( ( {t('Custom Seconds')} field.onChange(parseInt(e.target.value, 10) || 0) } /> )} /> ) : ( ( {t('Duration Value')} field.onChange(parseInt(e.target.value, 10) || 0) } /> )} /> )}
{/* Quota Reset */}

{t('Quota Reset')}

( {t('Reset Cycle')} )} /> ( {t('Custom Seconds')} field.onChange(parseInt(e.target.value, 10) || 0) } /> )} />
{/* Payment Config */}

{t('Third-party Payment Config')}

( Stripe Price ID )} /> ( Creem Product ID )} />
) }