✨ feat(subscribe): Improve error handling in subscription forms and update component props
This commit is contained in:
parent
f99c6048ad
commit
d28a10b6df
@ -40,8 +40,8 @@ import { unitConversion } from '@workspace/ui/utils';
|
|||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { formSchema, protocols } from './form-schema';
|
import { formSchema, protocols } from './form-schema';
|
||||||
|
|
||||||
interface NodeFormProps<T> {
|
interface NodeFormProps<T> {
|
||||||
onSubmit: (data: T) => Promise<boolean> | boolean;
|
onSubmit: (data: T) => Promise<boolean> | boolean;
|
||||||
initialValues?: T;
|
initialValues?: T;
|
||||||
@ -56,7 +56,7 @@ export default function NodeForm<T extends { [x: string]: any }>({
|
|||||||
loading,
|
loading,
|
||||||
trigger,
|
trigger,
|
||||||
title,
|
title,
|
||||||
}: NodeFormProps<T>) {
|
}: Readonly<NodeFormProps<T>>) {
|
||||||
const t = useTranslations('server.node');
|
const t = useTranslations('server.node');
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@ -853,8 +853,12 @@ export default function NodeForm<T extends { [x: string]: any }>({
|
|||||||
<Button
|
<Button
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={form.handleSubmit(handleSubmit, (errors) => {
|
onClick={form.handleSubmit(handleSubmit, (errors) => {
|
||||||
console.log(errors);
|
const keys = Object.keys(errors);
|
||||||
return errors;
|
for (const key of keys) {
|
||||||
|
const formattedKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||||
|
toast.error(`${t(`form.${formattedKey}`)} is ${errors[key]?.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}{' '}
|
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}{' '}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import { assign, shake } from 'radash';
|
import { assign, shake } from 'radash';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
interface SubscribeFormProps<T> {
|
interface SubscribeFormProps<T> {
|
||||||
@ -77,7 +78,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
loading,
|
loading,
|
||||||
trigger,
|
trigger,
|
||||||
title,
|
title,
|
||||||
}: SubscribeFormProps<T>) {
|
}: Readonly<SubscribeFormProps<T>>) {
|
||||||
const t = useTranslations('subscribe');
|
const t = useTranslations('subscribe');
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
@ -783,7 +784,17 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
>
|
>
|
||||||
{t('form.cancel')}
|
{t('form.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button disabled={loading} onClick={form.handleSubmit(handleSubmit)}>
|
<Button
|
||||||
|
disabled={loading}
|
||||||
|
onClick={form.handleSubmit(handleSubmit, (errors) => {
|
||||||
|
const keys = Object.keys(errors);
|
||||||
|
for (const key of keys) {
|
||||||
|
const formattedKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||||
|
toast.error(`${t(`form.${formattedKey}`)} is ${errors[key]?.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
>
|
||||||
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
|
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
|
||||||
{t('form.confirm')}
|
{t('form.confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -3,16 +3,16 @@
|
|||||||
import { Display } from '@/components/display';
|
import { Display } from '@/components/display';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
export function SubscribeDetail({
|
interface SubscribeDetailProps {
|
||||||
subscribe,
|
|
||||||
}: {
|
|
||||||
subscribe?: Partial<
|
subscribe?: Partial<
|
||||||
API.Subscribe & {
|
API.Subscribe & {
|
||||||
name: string;
|
name: string;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
}) {
|
}
|
||||||
|
|
||||||
|
export function SubscribeDetail({ subscribe }: Readonly<SubscribeDetailProps>) {
|
||||||
const t = useTranslations('subscribe.detail');
|
const t = useTranslations('subscribe.detail');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
import CouponInput from '@/components/subscribe/coupon-input';
|
import CouponInput from '@/components/subscribe/coupon-input';
|
||||||
import DurationSelector from '@/components/subscribe/duration-selector';
|
import DurationSelector from '@/components/subscribe/duration-selector';
|
||||||
import PaymentMethods from '@/components/subscribe/payment-methods';
|
import PaymentMethods from '@/components/subscribe/payment-methods';
|
||||||
import SubscribeSelector from '@/components/subscribe/subscribe-selector';
|
|
||||||
import useGlobalStore from '@/config/use-global';
|
import useGlobalStore from '@/config/use-global';
|
||||||
import { checkoutOrder, preCreateOrder, purchase } from '@/services/user/order';
|
import { checkoutOrder, preCreateOrder, purchase } from '@/services/user/order';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
@ -18,13 +17,12 @@ import { useCallback, useEffect, useState, useTransition } from 'react';
|
|||||||
import { SubscribeBilling } from './billing';
|
import { SubscribeBilling } from './billing';
|
||||||
import { SubscribeDetail } from './detail';
|
import { SubscribeDetail } from './detail';
|
||||||
|
|
||||||
export default function Purchase({
|
interface PurchaseProps {
|
||||||
subscribe,
|
|
||||||
setSubscribe,
|
|
||||||
}: {
|
|
||||||
subscribe?: API.Subscribe;
|
subscribe?: API.Subscribe;
|
||||||
setSubscribe: (subscribe?: API.Subscribe) => void;
|
setSubscribe: (subscribe?: API.Subscribe) => void;
|
||||||
}) {
|
}
|
||||||
|
|
||||||
|
export default function Purchase({ subscribe, setSubscribe }: Readonly<PurchaseProps>) {
|
||||||
const t = useTranslations('subscribe');
|
const t = useTranslations('subscribe');
|
||||||
const { getUserInfo } = useGlobalStore();
|
const { getUserInfo } = useGlobalStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -140,13 +138,6 @@ export default function Purchase({
|
|||||||
coupon={params.coupon}
|
coupon={params.coupon}
|
||||||
onChange={(value) => handleChange('coupon', value)}
|
onChange={(value) => handleChange('coupon', value)}
|
||||||
/>
|
/>
|
||||||
<SubscribeSelector
|
|
||||||
value={params.discount_subscribe_id}
|
|
||||||
data={order?.discount_list || []}
|
|
||||||
onChange={(value) => {
|
|
||||||
handleChange('discount_subscribe_id', value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<PaymentMethods
|
<PaymentMethods
|
||||||
value={params.payment!}
|
value={params.payment!}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
import CouponInput from '@/components/subscribe/coupon-input';
|
import CouponInput from '@/components/subscribe/coupon-input';
|
||||||
import DurationSelector from '@/components/subscribe/duration-selector';
|
import DurationSelector from '@/components/subscribe/duration-selector';
|
||||||
import PaymentMethods from '@/components/subscribe/payment-methods';
|
import PaymentMethods from '@/components/subscribe/payment-methods';
|
||||||
import SubscribeSelector from '@/components/subscribe/subscribe-selector';
|
|
||||||
import useGlobalStore from '@/config/use-global';
|
import useGlobalStore from '@/config/use-global';
|
||||||
import { checkoutOrder, preCreateOrder, renewal } from '@/services/user/order';
|
import { checkoutOrder, preCreateOrder, renewal } from '@/services/user/order';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
@ -24,7 +23,12 @@ import { useCallback, useEffect, useState, useTransition } from 'react';
|
|||||||
import { SubscribeBilling } from './billing';
|
import { SubscribeBilling } from './billing';
|
||||||
import { SubscribeDetail } from './detail';
|
import { SubscribeDetail } from './detail';
|
||||||
|
|
||||||
export default function Renewal({ token, subscribe }: { token: string; subscribe: API.Subscribe }) {
|
interface RenewalProps {
|
||||||
|
token: string;
|
||||||
|
subscribe: API.Subscribe;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Renewal({ token, subscribe }: Readonly<RenewalProps>) {
|
||||||
const t = useTranslations('subscribe');
|
const t = useTranslations('subscribe');
|
||||||
const { getUserInfo } = useGlobalStore();
|
const { getUserInfo } = useGlobalStore();
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
@ -141,13 +145,6 @@ export default function Renewal({ token, subscribe }: { token: string; subscribe
|
|||||||
coupon={params.coupon}
|
coupon={params.coupon}
|
||||||
onChange={(value) => handleChange('coupon', value)}
|
onChange={(value) => handleChange('coupon', value)}
|
||||||
/>
|
/>
|
||||||
<SubscribeSelector
|
|
||||||
value={params.discount_subscribe_id}
|
|
||||||
data={order?.discount_list || []}
|
|
||||||
onChange={(value) => {
|
|
||||||
handleChange('discount_subscribe_id', value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<PaymentMethods
|
<PaymentMethods
|
||||||
value={params.payment!}
|
value={params.payment!}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user