diff --git a/apps/user/components/auth/oauth-methods.tsx b/apps/user/components/auth/oauth-methods.tsx
new file mode 100644
index 0000000..c805e65
--- /dev/null
+++ b/apps/user/components/auth/oauth-methods.tsx
@@ -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 && (
+ <>
+
+
+ Or continue with
+
+
+
+ {OAUTH_METHODS?.map((method: any) => {
+ return (
+
+ );
+ })}
+
+ >
+ )
+ );
+}
diff --git a/apps/user/components/main/product-showcase.tsx b/apps/user/components/main/product-showcase/content.tsx
similarity index 90%
rename from apps/user/components/main/product-showcase.tsx
rename to apps/user/components/main/product-showcase/content.tsx
index 4083e63..8f859a7 100644
--- a/apps/user/components/main/product-showcase.tsx
+++ b/apps/user/components/main/product-showcase/content.tsx
@@ -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 (
- {data?.map((item, index) => (
+ {subscriptionData?.map((item, index) => (
- {t('subscribe')}
+
+ {t('subscribe')}
+
diff --git a/apps/user/components/main/product-showcase/index.tsx b/apps/user/components/main/product-showcase/index.tsx
new file mode 100644
index 0000000..27046de
--- /dev/null
+++ b/apps/user/components/main/product-showcase/index.tsx
@@ -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
;
+ } catch (error) {
+ return null;
+ }
+}
diff --git a/apps/user/components/subscribe/payment-methods.tsx b/apps/user/components/subscribe/payment-methods.tsx
index d440fe9..c768ce1 100644
--- a/apps/user/components/subscribe/payment-methods.tsx
+++ b/apps/user/components/subscribe/payment-methods.tsx
@@ -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
= ({ value, onChange }) => {
+const PaymentMethods: React.FC = ({ 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 (
<>
{t('paymentMethod')}
-
+
{data?.map((item) => (
diff --git a/apps/user/components/subscribe/purchase.tsx b/apps/user/components/subscribe/purchase.tsx
index 88e1ce7..4ec165f 100644
--- a/apps/user/components/subscribe/purchase.tsx
+++ b/apps/user/components/subscribe/purchase.tsx
@@ -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
) {
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}`,
});
diff --git a/apps/user/components/subscribe/renewal.tsx b/apps/user/components/subscribe/renewal.tsx
index f5ebcf8..c8faf58 100644
--- a/apps/user/components/subscribe/renewal.tsx
+++ b/apps/user/components/subscribe/renewal.tsx
@@ -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) {
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}`,
});
diff --git a/apps/user/components/subscribe/reset-traffic.tsx b/apps/user/components/subscribe/reset-traffic.tsx
index 42d8413..33640a8 100644
--- a/apps/user/components/subscribe/reset-traffic.tsx
+++ b/apps/user/components/subscribe/reset-traffic.tsx
@@ -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(
- '/v1/common/site/subscribe',
- {
- method: 'GET',
- ...(options || {}),
- },
- );
-}
-
/** Get Tos Content GET /v1/common/site/tos */
export async function getTos(options?: { [key: string]: any }) {
return request('/v1/common/site/tos', {
diff --git a/apps/user/services/common/typings.d.ts b/apps/user/services/common/typings.d.ts
index 566eeb9..878dfce 100644
--- a/apps/user/services/common/typings.d.ts
+++ b/apps/user/services/common/typings.d.ts
@@ -90,17 +90,6 @@ declare namespace API {
enabled: boolean;
};
- type CheckoutOrderRequest = {
- orderNo: string;
- returnUrl?: string;
- };
-
- type CheckoutOrderResponse = {
- type: string;
- checkout_url?: string;
- stripe?: StripePayment;
- };
-
type CheckUserParams = {
email: string;
};
@@ -175,7 +164,7 @@ declare namespace API {
};
type GetAvailablePaymentMethodsResponse = {
- list: PaymentConfig[];
+ list: PaymenMethod[];
};
type GetGlobalConfigResponse = {
@@ -196,14 +185,24 @@ declare namespace API {
protocol: string[];
};
- type GetSubscriptionResponse = {
- list: Subscribe[];
- };
-
type GetTosResponse = {
tos_content: string;
};
+ type GetUserSubscribeTrafficLogsRequest = {
+ page: number;
+ size: number;
+ user_id: number;
+ subscribe_id: number;
+ start_time: number;
+ end_time: number;
+ };
+
+ type GetUserSubscribeTrafficLogsResponse = {
+ list: TrafficLog[];
+ total: number;
+ };
+
type GoogleLoginCallbackRequest = {
code: string;
state: string;
@@ -329,6 +328,16 @@ declare namespace API {
updated_at: number;
};
+ type PaymenMethod = {
+ id: number;
+ name: string;
+ mark: string;
+ icon: string;
+ fee_mode: number;
+ fee_percent: number;
+ fee_amount: number;
+ };
+
type PaymentConfig = {
id: number;
name: string;
@@ -417,6 +426,21 @@ declare namespace API {
list: OrderDetail[];
};
+ type QuerySubscribeGroupListResponse = {
+ list: SubscribeGroup[];
+ total: number;
+ };
+
+ type QuerySubscribeListResponse = {
+ list: Subscribe[];
+ total: number;
+ };
+
+ type QueryUserAffiliateListResponse = {
+ list: UserAffiliate[];
+ total: number;
+ };
+
type RechargeOrderRequest = {
amount: number;
payment: string;
diff --git a/apps/user/services/user/index.ts b/apps/user/services/user/index.ts
index a3487d7..f988131 100644
--- a/apps/user/services/user/index.ts
+++ b/apps/user/services/user/index.ts
@@ -1,11 +1,12 @@
// @ts-ignore
-/* eslint-disable */
+
// API 更新时间:
// API 唯一标识:
import * as announcement from './announcement';
import * as document from './document';
import * as order from './order';
import * as payment from './payment';
+import * as portal from './portal';
import * as subscribe from './subscribe';
import * as ticket from './ticket';
import * as user from './user';
@@ -14,6 +15,7 @@ export default {
document,
order,
payment,
+ portal,
subscribe,
ticket,
user,
diff --git a/apps/user/services/user/order.ts b/apps/user/services/user/order.ts
index 59db689..aeebc8d 100644
--- a/apps/user/services/user/order.ts
+++ b/apps/user/services/user/order.ts
@@ -2,21 +2,6 @@
/* eslint-disable */
import request from '@/utils/request';
-/** Checkout order POST /v1/public/order/checkout */
-export async function checkoutOrder(
- body: API.CheckoutOrderRequest,
- options?: { [key: string]: any },
-) {
- return request('/v1/public/order/checkout', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- data: body,
- ...(options || {}),
- });
-}
-
/** Close order POST /v1/public/order/close */
export async function closeOrder(body: API.CloseOrderRequest, options?: { [key: string]: any }) {
return request('/v1/public/order/close', {
diff --git a/apps/user/services/user/portal.ts b/apps/user/services/user/portal.ts
new file mode 100644
index 0000000..abac9f9
--- /dev/null
+++ b/apps/user/services/user/portal.ts
@@ -0,0 +1,91 @@
+// @ts-ignore
+/* eslint-disable */
+import request from '@/utils/request';
+
+/** Purchase Checkout POST /v1/public/portal/order/checkout */
+export async function purchaseCheckout(
+ body: API.CheckoutOrderRequest,
+ options?: { [key: string]: any },
+) {
+ return request(
+ '/v1/public/portal/order/checkout',
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ data: body,
+ ...(options || {}),
+ },
+ );
+}
+
+/** Query Purchase Order GET /v1/public/portal/order/status */
+export async function queryPurchaseOrder(
+ // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
+ params: API.QueryPurchaseOrderParams,
+ options?: { [key: string]: any },
+) {
+ return request(
+ '/v1/public/portal/order/status',
+ {
+ method: 'GET',
+ params: {
+ ...params,
+ },
+ ...(options || {}),
+ },
+ );
+}
+
+/** Get available payment methods GET /v1/public/portal/payment-method */
+export async function getAvailablePaymentMethods(options?: { [key: string]: any }) {
+ return request(
+ '/v1/public/portal/payment-method',
+ {
+ method: 'GET',
+ ...(options || {}),
+ },
+ );
+}
+
+/** Pre Purchase Order POST /v1/public/portal/pre */
+export async function prePurchaseOrder(
+ body: API.PrePurchaseOrderRequest,
+ options?: { [key: string]: any },
+) {
+ return request('/v1/public/portal/pre', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ data: body,
+ ...(options || {}),
+ });
+}
+
+/** Purchase subscription POST /v1/public/portal/purchase */
+export async function purchase(body: API.PortalPurchaseRequest, options?: { [key: string]: any }) {
+ return request(
+ '/v1/public/portal/purchase',
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ data: body,
+ ...(options || {}),
+ },
+ );
+}
+
+/** Get Subscription GET /v1/public/portal/subscribe */
+export async function getSubscription(options?: { [key: string]: any }) {
+ return request(
+ '/v1/public/portal/subscribe',
+ {
+ method: 'GET',
+ ...(options || {}),
+ },
+ );
+}
diff --git a/apps/user/services/user/typings.d.ts b/apps/user/services/user/typings.d.ts
index 06e50d6..4e4b8c8 100644
--- a/apps/user/services/user/typings.d.ts
+++ b/apps/user/services/user/typings.d.ts
@@ -187,7 +187,7 @@ declare namespace API {
};
type GetAvailablePaymentMethodsResponse = {
- list: PaymentConfig[];
+ list: PaymenMethod[];
};
type GetLoginLogParams = {
@@ -224,6 +224,24 @@ declare namespace API {
total: number;
};
+ type GetSubscriptionResponse = {
+ list: Subscribe[];
+ };
+
+ type GetUserSubscribeTrafficLogsRequest = {
+ page: number;
+ size: number;
+ user_id: number;
+ subscribe_id: number;
+ start_time: number;
+ end_time: number;
+ };
+
+ type GetUserSubscribeTrafficLogsResponse = {
+ list: TrafficLog[];
+ total: number;
+ };
+
type GetUserTicketDetailRequest = {
id: number;
};
@@ -351,6 +369,16 @@ declare namespace API {
updated_at: number;
};
+ type PaymenMethod = {
+ id: number;
+ name: string;
+ mark: string;
+ icon: string;
+ fee_mode: number;
+ fee_percent: number;
+ fee_amount: number;
+ };
+
type PaymentConfig = {
id: number;
name: string;
@@ -364,6 +392,21 @@ declare namespace API {
enable: boolean;
};
+ type PortalPurchaseRequest = {
+ identifier: string;
+ platform: string;
+ password?: string;
+ payment: string;
+ subscribe_id: number;
+ quantity: number;
+ coupon?: string;
+ turnstile_token?: string;
+ };
+
+ type PortalPurchaseResponse = {
+ order_no: string;
+ };
+
type PreOrderResponse = {
price: number;
amount: number;
@@ -374,6 +417,22 @@ declare namespace API {
fee_amount: number;
};
+ type PrePurchaseOrderRequest = {
+ payment: string;
+ subscribe_id: number;
+ quantity: number;
+ coupon?: string;
+ };
+
+ type PrePurchaseOrderResponse = {
+ price: number;
+ amount: number;
+ discount: number;
+ coupon: string;
+ coupon_discount: number;
+ fee_amount: number;
+ };
+
type PreRenewalOrderResponse = {
orderNo: string;
};
@@ -467,6 +526,30 @@ declare namespace API {
list: OrderDetail[];
};
+ type QueryPurchaseOrderParams = {
+ order_no: string;
+ };
+
+ type QueryPurchaseOrderRequest = {
+ order_no: string;
+ };
+
+ type QueryPurchaseOrderResponse = {
+ order_no: string;
+ subscribe: Subscribe;
+ quantity: number;
+ price: number;
+ amount: number;
+ discount: number;
+ coupon: string;
+ coupon_discount: number;
+ fee_amount: number;
+ payment: string;
+ status: number;
+ created_at: number;
+ token?: string;
+ };
+
type QuerySubscribeGroupListResponse = {
list: SubscribeGroup[];
total: number;
diff --git a/apps/user/utils/common.ts b/apps/user/utils/common.ts
index 28ac162..932315f 100644
--- a/apps/user/utils/common.ts
+++ b/apps/user/utils/common.ts
@@ -52,6 +52,7 @@ export function Logout() {
const pathname = location.pathname;
if (
!['', '/', '/auth', '/tos', '/privacy-policy'].includes(pathname) &&
+ !pathname.startsWith('/purchasing') &&
!pathname.startsWith('/oauth/')
) {
setRedirectUrl(location.pathname);