feat(subscription): Refactor subscription handling and update imports for better organization

This commit is contained in:
web@ppanel
2025-03-08 12:34:23 +07:00
parent 3222016799
commit 2215c7f2b9
27 changed files with 1042 additions and 180 deletions
@@ -0,0 +1,56 @@
'use client';
import useGlobalStore from '@/config/use-global';
import { oAuthLogin } from '@/services/common/oauth';
import { Button } from '@workspace/ui/components/button';
import { Icon } from '@workspace/ui/custom-components/icon';
const icons = {
apple: 'uil:apple',
google: 'logos:google-icon',
facebook: 'logos:facebook',
github: 'uil:github',
telegram: 'logos:telegram',
};
export function OAuthMethods() {
const { common } = useGlobalStore();
const { oauth_methods } = common;
const OAUTH_METHODS = oauth_methods?.filter(
(method) => !['mobile', 'email', 'device'].includes(method),
);
return (
OAUTH_METHODS?.length > 0 && (
<>
<div className='after:border-border relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t'>
<span className='bg-background text-muted-foreground relative z-10 px-2'>
Or continue with
</span>
</div>
<div className='mt-6 flex justify-center gap-4 *:size-12 *:p-2'>
{OAUTH_METHODS?.map((method: any) => {
return (
<Button
key={method}
variant='ghost'
size='icon'
asChild
onClick={async () => {
const { data } = await oAuthLogin({
method,
redirect: `${window.location.origin}/oauth/${method}`,
});
if (data.data?.redirect) {
window.location.href = data.data?.redirect;
}
}}
>
<Icon icon={icons[method as keyof typeof icons]} />
</Button>
);
})}
</div>
</>
)
);
}
@@ -2,8 +2,7 @@
import { Display } from '@/components/display';
import { SubscribeDetail } from '@/components/subscribe/detail';
import { getSubscription } from '@/services/common/common';
import { useQuery } from '@tanstack/react-query';
import useGlobalStore from '@/config/use-global';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardFooter, CardHeader } from '@workspace/ui/components/card';
import { Separator } from '@workspace/ui/components/separator';
@@ -14,19 +13,15 @@ import { useTranslations } from 'next-intl';
import Link from 'next/link';
import { Key, ReactNode } from 'react';
export function ProductShowcase() {
interface ProductShowcaseProps {
subscriptionData: API.Subscribe[];
}
export function Content({ subscriptionData }: ProductShowcaseProps) {
const t = useTranslations('index');
const { data } = useQuery({
queryKey: ['getSubscription'],
queryFn: async () => {
const { data } = await getSubscription({
skipErrorHandler: true,
});
return data.data?.list || [];
},
});
if (data?.length === 0) return null;
const { user } = useGlobalStore();
return (
<motion.section
initial={{ opacity: 0 }}
@@ -51,7 +46,7 @@ export function ProductShowcase() {
{t('product_showcase_description')}
</motion.p>
<div className='mx-auto flex flex-wrap justify-center gap-8 overflow-x-auto overflow-y-hidden *:max-w-80 *:flex-auto'>
{data?.map((item, index) => (
{subscriptionData?.map((item, index) => (
<motion.div
key={item.id}
initial={{ opacity: 0, y: 50 }}
@@ -132,7 +127,9 @@ export function ProductShowcase() {
className='absolute bottom-0 left-0 w-full rounded-b-xl rounded-t-none'
asChild
>
<Link href='/subscribe'>{t('subscribe')}</Link>
<Link href={user ? '/subscribe' : `/purchasing?id=${item.id}`}>
{t('subscribe')}
</Link>
</Button>
</motion.div>
</CardFooter>
@@ -0,0 +1,17 @@
import { getSubscription } from '@/services/user/portal';
import { Content } from './content';
export async function ProductShowcase() {
try {
const { data } = await getSubscription({
skipErrorHandler: true,
});
const subscriptionList = data.data?.list || [];
if (subscriptionList.length === 0) return null;
return <Content subscriptionData={subscriptionList} />;
} catch (error) {
return null;
}
}
@@ -1,6 +1,8 @@
'use client';
import { getAvailablePaymentMethods } from '@/services/user/payment';
import { getAvailablePaymentMethods } from '@/services/user/portal';
// import { getAvailablePaymentMethods } from '@/services/user/payment';
// import { getAvailablePaymentMethods } from '@/services/user/payment';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { RadioGroup, RadioGroupItem } from '@workspace/ui/components/radio-group';
@@ -11,22 +13,30 @@ import React, { memo } from 'react';
interface PaymentMethodsProps {
value: string;
onChange: (value: string) => void;
balance?: boolean;
}
const PaymentMethods: React.FC<PaymentMethodsProps> = ({ value, onChange }) => {
const PaymentMethods: React.FC<PaymentMethodsProps> = ({ value, onChange, balance = true }) => {
const t = useTranslations('subscribe');
const { data } = useQuery({
queryKey: ['getAvailablePaymentMethods'],
queryKey: ['getAvailablePaymentMethods', { balance }],
queryFn: async () => {
const { data } = await getAvailablePaymentMethods();
return data.data?.list || [];
const methods = data.data?.list || [];
if (!value && methods[0]?.mark) onChange(methods[0]?.mark);
if (balance) return methods;
return methods.filter((item) => item.mark !== 'balance');
},
});
return (
<>
<div className='font-semibold'>{t('paymentMethod')}</div>
<RadioGroup className='grid grid-cols-5 gap-2' value={value} onValueChange={onChange}>
<RadioGroup
className='grid grid-cols-2 gap-2 md:grid-cols-5'
value={value}
onValueChange={onChange}
>
{data?.map((item) => (
<div key={item.mark}>
<RadioGroupItem value={item.mark} id={item.mark} className='peer sr-only' />
+3 -2
View File
@@ -4,7 +4,8 @@ import CouponInput from '@/components/subscribe/coupon-input';
import DurationSelector from '@/components/subscribe/duration-selector';
import PaymentMethods from '@/components/subscribe/payment-methods';
import useGlobalStore from '@/config/use-global';
import { checkoutOrder, preCreateOrder, purchase } from '@/services/user/order';
import { preCreateOrder, purchase } from '@/services/user/order';
import { purchaseCheckout } from '@/services/user/portal';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent } from '@workspace/ui/components/card';
@@ -69,7 +70,7 @@ export default function Purchase({ subscribe, setSubscribe }: Readonly<PurchaseP
const response = await purchase(params as API.PurchaseOrderRequest);
const orderNo = response.data.data?.order_no;
if (orderNo) {
const { data } = await checkoutOrder({
const { data } = await purchaseCheckout({
orderNo,
returnUrl: `${window.location.origin}/payment?order_no=${orderNo}`,
});
+3 -2
View File
@@ -1,8 +1,9 @@
'use client';
import useGlobalStore from '@/config/use-global';
import { checkoutOrder, recharge } from '@/services/user/order';
import { recharge } from '@/services/user/order';
import { getAvailablePaymentMethods } from '@/services/user/payment';
import { purchaseCheckout } from '@/services/user/portal';
import { useQuery } from '@tanstack/react-query';
import { Button, ButtonProps } from '@workspace/ui/components/button';
import {
@@ -133,7 +134,7 @@ export default function Recharge(props: Readonly<ButtonProps>) {
const response = await recharge(params);
const orderNo = response.data.data?.order_no;
if (orderNo) {
const { data } = await checkoutOrder({
const { data } = await purchaseCheckout({
orderNo,
returnUrl: `${window.location.origin}/payment?order_no=${orderNo}`,
});
+3 -2
View File
@@ -4,7 +4,8 @@ import CouponInput from '@/components/subscribe/coupon-input';
import DurationSelector from '@/components/subscribe/duration-selector';
import PaymentMethods from '@/components/subscribe/payment-methods';
import useGlobalStore from '@/config/use-global';
import { checkoutOrder, preCreateOrder, renewal } from '@/services/user/order';
import { preCreateOrder, renewal } from '@/services/user/order';
import { purchaseCheckout } from '@/services/user/portal';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent } from '@workspace/ui/components/card';
@@ -77,7 +78,7 @@ export default function Renewal({ id, subscribe }: Readonly<RenewalProps>) {
const response = await renewal(params as API.RenewalOrderRequest);
const orderNo = response.data.data?.order_no;
if (orderNo) {
const { data } = await checkoutOrder({
const { data } = await purchaseCheckout({
orderNo,
returnUrl: `${window.location.origin}/payment?order_no=${orderNo}`,
});
@@ -2,7 +2,8 @@
import { Display } from '@/components/display';
import useGlobalStore from '@/config/use-global';
import { checkoutOrder, resetTraffic } from '@/services/user/order';
import { resetTraffic } from '@/services/user/order';
import { purchaseCheckout } from '@/services/user/portal';
import { Button } from '@workspace/ui/components/button';
import {
Dialog,
@@ -84,7 +85,7 @@ export default function ResetTraffic({ id, replacement }: Readonly<ResetTrafficP
const response = await resetTraffic(params);
const orderNo = response.data.data?.order_no;
if (orderNo) {
const { data } = await checkoutOrder({
const { data } = await purchaseCheckout({
orderNo,
returnUrl: `${window.location.origin}/payment?order_no=${orderNo}`,
});