diff --git a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx index 0b207c0..53688e7 100644 --- a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx +++ b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx @@ -77,7 +77,7 @@ export default function Content() { }, }); - /*const { data } = useQuery({ + const { data } = useQuery({ queryKey: ['getStat'], queryFn: async () => { const { data } = await getStat({ @@ -86,13 +86,7 @@ export default function Content() { return data.data; }, refetchOnWindowFocus: false, - });*/ - const data = { - user: 1, - node: 2, - country: 0, - protocol: ['vmess', 'vless'], - }; + }); const { data: announcementData } = useQuery({ queryKey: ['queryAnnouncement'], @@ -142,9 +136,11 @@ export default function Content() { {/* 账户概况 Card */}
-

- {t('accountOverview')} -

+ {userSubscribe?.[0]?.status === 1 ? ( +

+ {t('accountOverview')} +

+ ) : null}

{user?.auth_methods?.[0]?.auth_identifier}

@@ -204,12 +200,15 @@ export default function Content() {
{t('availableDevices')}
-
-
-
-
-
-
+ {Array.from({ length: userSubscribe?.[0]?.subscribe.device_limit }).map( + (_, index) => { + return ( +
1 ? 'bg-[#225BA9]' : 'bg-[#D9D9D9]'}`} + >
+ ); + }, + )}
@@ -314,7 +313,7 @@ export default function Content() {
- {userSubscribe?.[0] && data.protocol ? ( + {userSubscribe?.[0] && data?.protocol ? (

{t('copySubscriptionLinkOrScanQrCode')} diff --git a/apps/user/app/(main)/(content)/(user)/order/page.tsx b/apps/user/app/(main)/(content)/(user)/order/page.tsx index 1a7d709..efe9961 100644 --- a/apps/user/app/(main)/(content)/(user)/order/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/order/page.tsx @@ -4,11 +4,13 @@ import { Display } from '@/components/display'; import { Empty } from '@/components/empty'; import { ProList, ProListActions } from '@/components/pro-list'; import { closeOrder, queryOrderList } from '@/services/user/order'; -import { Button } from '@workspace/airo-ui/components/button'; +import { purchaseCheckout } from '@/services/user/portal'; +import { AiroButton } from '@workspace/airo-ui/components/AiroButton'; import { Card, CardContent } from '@workspace/airo-ui/components/card'; import { formatDate } from '@workspace/airo-ui/utils'; import { useTranslations } from 'next-intl'; import { useRef } from 'react'; +import { toast } from 'sonner'; import OrderDetailDialog from './components/OrderDetailDialog'; export default function Page() { @@ -16,6 +18,20 @@ export default function Page() { const ref = useRef(null); const OrderDetailDialogRef = useRef(null); + + const handlePayment = (orderNo) => { + const data = await purchaseCheckout({ + orderNo: orderNo, + returnUrl: window.location.href, + }); + if (data.data?.type === 'url' && data.data.checkout_url) { + window.open(data.data.checkout_url, '_blank'); + } else { + toast.success(t('paymentSuccess')); + ref?.current.reset(); + } + }; + return (

> @@ -38,26 +54,32 @@ export default function Page() {
{item.status === 1 ? ( <> - - + ) : ( - + )}
diff --git a/apps/user/app/(main)/(content)/(user)/sidebar-left.tsx b/apps/user/app/(main)/(content)/(user)/sidebar-left.tsx index e170bd5..948da29 100644 --- a/apps/user/app/(main)/(content)/(user)/sidebar-left.tsx +++ b/apps/user/app/(main)/(content)/(user)/sidebar-left.tsx @@ -1,4 +1,5 @@ 'use client'; +import LanguageSwitch from '@/components/language-switch'; import SvgIcon from '@/components/SvgIcon'; import { UserNav } from '@/components/user-nav'; import { navs } from '@/config/navs'; @@ -24,7 +25,7 @@ export function SidebarLeft({ ...props }: React.ComponentProps)
@@ -35,7 +36,7 @@ export function SidebarLeft({ ...props }: React.ComponentProps) 'absolute -left-2.5 top-2.5 -z-10 h-full w-full rounded-[30px] bg-[#225BA9] md:hidden' } >
-
+
) -
+
{t(nav.title)} @@ -78,7 +79,10 @@ export function SidebarLeft({ ...props }: React.ComponentProps) - + +
+ +
diff --git a/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx b/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx index ccb227d..79b8f94 100644 --- a/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/subscribe/page.tsx @@ -97,12 +97,6 @@ export default function Page() { -20% {/* 小三角箭头 */} - {/* */} setCreate({ open })}> - + {t('createTicket')} @@ -183,23 +178,20 @@ export default function Page() { {item.status !== 4 ? ( <> - + {t('close')} @@ -217,9 +209,13 @@ export default function Page() { /> ) : ( - + )} @@ -241,15 +237,9 @@ export default function Page() { - + ); diff --git a/apps/user/app/(main)/(content)/(user)/wallet/page.tsx b/apps/user/app/(main)/(content)/(user)/wallet/page.tsx index 54eec4e..5f16da2 100644 --- a/apps/user/app/(main)/(content)/(user)/wallet/page.tsx +++ b/apps/user/app/(main)/(content)/(user)/wallet/page.tsx @@ -29,11 +29,7 @@ export default function Page() {

{t('assetOverview')} - +

diff --git a/apps/user/assets/svg-icon/language.svg b/apps/user/assets/svg-icon/language.svg new file mode 100644 index 0000000..64da1cd --- /dev/null +++ b/apps/user/assets/svg-icon/language.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/user/components/affiliate/index.tsx b/apps/user/components/affiliate/index.tsx index 7fb60b0..389db38 100644 --- a/apps/user/components/affiliate/index.tsx +++ b/apps/user/components/affiliate/index.tsx @@ -286,7 +286,7 @@ export default function Affiliate() { className='h-6 border-0 p-0 text-center text-sm focus-visible:ring-0 sm:h-8' style={{ width: `${Math.max(3, String(count).length + 1)}ch` }} /> - {t('users')} + users
+ + {t('walletRecharge')} + diff --git a/apps/user/components/user-nav.tsx b/apps/user/components/user-nav.tsx index 4277ba1..21b4e12 100644 --- a/apps/user/components/user-nav.tsx +++ b/apps/user/components/user-nav.tsx @@ -28,18 +28,18 @@ export function UserNav({ from = '' }: { from?: string }) { {from === 'profile' ? ( -
- +
+ - + {user?.auth_methods?.[0]?.auth_identifier.toUpperCase().charAt(0)} -
+
{user?.auth_methods?.[0]?.auth_identifier.split('@')[0]}
@@ -61,13 +61,13 @@ export function UserNav({ from = '' }: { from?: string }) { forceMount align='end' side={from === 'profile' ? (isMobile ? 'top' : 'right') : undefined} - className='flex w-[var(--sidebar-width)] flex-col gap-1 rounded-[42px] border-0 bg-transparent pl-[26px] pr-4 shadow-none md:w-64 md:gap-3 md:border md:bg-white md:p-3 md:shadow-md' + className='mt-[1px] flex w-[var(--sidebar-width)] flex-col gap-1 rounded-[28px] border-0 bg-transparent pl-[26px] pr-4 shadow-none md:w-48 md:gap-3 md:border md:bg-white md:p-3' style={{ '--sidebar-width': '14rem', }} > -
- +
+ -
-

+

+

{user?.auth_methods?.[0]?.auth_identifier.split('@')[0]}

-

+

{user?.auth_methods?.[0]?.auth_identifier}

@@ -101,9 +101,9 @@ export function UserNav({ from = '' }: { from?: string }) { toggleSidebar(); router.push(`${item.url}`); }} - className='flex cursor-pointer items-center gap-3 rounded-full bg-white px-5 py-2 text-base font-medium focus:bg-[#0F2C53] focus:text-white data-[active=true]:bg-[#0F2C53] data-[active=true]:text-white md:text-xl' + className='flex cursor-pointer items-center gap-3 rounded-full bg-white px-5 py-2.5 text-base font-medium focus:bg-[#0F2C53] focus:text-white data-[active=true]:bg-[#0F2C53] data-[active=true]:text-white md:text-sm' > - + {t(item.title)} ))} @@ -112,14 +112,9 @@ export function UserNav({ from = '' }: { from?: string }) { Logout(); setUser(); }} - className='flex cursor-pointer items-center gap-3 rounded-full bg-[#E22C2E] px-5 py-2 text-base font-medium text-white focus:bg-[#E22C2E] focus:text-white md:bg-white md:text-xl md:text-[#0F2C53]' + className='flex cursor-pointer items-center gap-3 rounded-full bg-[#E22C2E] px-5 py-2 text-base font-medium text-white focus:bg-[#E22C2E] focus:text-white md:bg-white md:text-sm md:text-[#0F2C53]' > - + {t('logout')} diff --git a/apps/user/locales/en-US/subscribe.json b/apps/user/locales/en-US/subscribe.json index 3bb32a7..6cbac7f 100644 --- a/apps/user/locales/en-US/subscribe.json +++ b/apps/user/locales/en-US/subscribe.json @@ -43,6 +43,7 @@ }, "monthlyPlan": "Monthly Plan", "paymentMethod": "Payment Method", + "paymentSuccess": "Success", "productDescription": "Product Description", "products": "Products", "purchaseDuration": "Purchase Duration", diff --git a/apps/user/locales/en-US/ticket.json b/apps/user/locales/en-US/ticket.json index 0046be9..17628f7 100644 --- a/apps/user/locales/en-US/ticket.json +++ b/apps/user/locales/en-US/ticket.json @@ -1,7 +1,7 @@ { "cancel": "Cancel", "check": "Check", - "close": "Close", + "close": "Close Ticket", "closeSuccess": "Closed successfully", "closeWarning": "Once closed, the ticket cannot be operated on. Please proceed with caution.", "confirm": "Confirm", diff --git a/apps/user/locales/zh-CN/subscribe.json b/apps/user/locales/zh-CN/subscribe.json index 6d03e6b..9c4d22f 100644 --- a/apps/user/locales/zh-CN/subscribe.json +++ b/apps/user/locales/zh-CN/subscribe.json @@ -43,6 +43,7 @@ }, "monthlyPlan": "月付套餐", "paymentMethod": "支付方式", + "paymentSuccess": "订阅成功", "productDescription": "商品描述", "products": "商品", "purchaseDuration": "购买时长", diff --git a/apps/user/locales/zh-CN/ticket.json b/apps/user/locales/zh-CN/ticket.json index 215f86c..2834ebf 100644 --- a/apps/user/locales/zh-CN/ticket.json +++ b/apps/user/locales/zh-CN/ticket.json @@ -1,7 +1,7 @@ { "cancel": "取消", "check": "查看", - "close": "关闭", + "close": "关闭工单", "closeSuccess": "工单关闭成功", "closeWarning": "关闭工单后将无法继续回复。", "confirm": "确认", diff --git a/packages/airo-ui/src/components/AiroButton.tsx b/packages/airo-ui/src/components/AiroButton.tsx new file mode 100644 index 0000000..44ffa47 --- /dev/null +++ b/packages/airo-ui/src/components/AiroButton.tsx @@ -0,0 +1,49 @@ +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@workspace/airo-ui/lib/utils'; + +const buttonVariants = cva( + 'px-6 rounded-full inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + { + variants: { + variant: { + default: 'bg-[#0F2C53] text-primary-foreground shadow hover:bg-[#225BA9]', + primary: 'bg-[#A8D4ED] text-primary-foreground shadow hover:bg-[#225BA9] ', + danger: 'bg-[#F8BFD2] text-primary-foreground shadow hover:bg-[#FF4248]', + destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', + outline: + 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-8 min-w-[100px]', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const AiroButton = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + }, +); +AiroButton.displayName = 'AiroButton'; + +export { AiroButton, buttonVariants }; diff --git a/packages/airo-ui/src/custom-components/pro-list/pro-list.tsx b/packages/airo-ui/src/custom-components/pro-list/pro-list.tsx index 9cb0989..eb9ebff 100644 --- a/packages/airo-ui/src/custom-components/pro-list/pro-list.tsx +++ b/packages/airo-ui/src/custom-components/pro-list/pro-list.tsx @@ -148,7 +148,11 @@ export function ProList>({
{params && params?.length > 0 && ( <> - diff --git a/packages/airo-ui/tailwind.config.ts b/packages/airo-ui/tailwind.config.ts index 06864bc..b0be8ce 100644 --- a/packages/airo-ui/tailwind.config.ts +++ b/packages/airo-ui/tailwind.config.ts @@ -7,8 +7,8 @@ const config = { content: [ 'app/**/*.{ts,tsx}', 'components/**/*.{ts,tsx}', - '../../packages/ui/src/components/**/*.{ts,tsx}', - '../../packages/ui/src/custom-components/**/*.{ts,tsx}', + '../../packages/airo-ui/src/components/**/*.{ts,tsx}', + '../../packages/airo-ui/src/custom-components/**/*.{ts,tsx}', ], theme: { extend: {