diff --git a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx index 2791295..3025572 100644 --- a/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx +++ b/apps/user/app/(main)/(content)/(user)/dashboard/content.tsx @@ -46,6 +46,7 @@ import { } from '@workspace/airo-ui/components/alert-dialog'; import { Popover, PopoverContent, PopoverTrigger } from '@workspace/airo-ui/components/popover'; import { Tabs, TabsList, TabsTrigger } from '@workspace/airo-ui/components/tabs'; +import { default as Airo_Empty } from '@workspace/airo-ui/custom-components/empty'; import { differenceInDays, formatDate } from '@workspace/airo-ui/utils'; import { QRCodeCanvas } from 'qrcode.react'; import { CopyToClipboard } from 'react-copy-to-clipboard'; @@ -257,14 +258,11 @@ export default function Content() { ) : ( -
{t('noPlanAvailable')}
+ )} {/* 网站公告 Card */} -

{t('siteAnnouncements')} @@ -279,29 +277,40 @@ export default function Content() { ) : null}

-
- {/* 置顶公告 */} - {announcementData?.map((item) => { - return ( -
-

- {item.pinned && t('pinnedAnnouncement')}{' '} - - {item.content} - -

-
- popupRef.current?.open(item)} - > - {t('viewDetails')} - -
-
- ); - })} -
+ {announcementData?.length ? ( + <> +
+ {/* 置顶公告 */} + {announcementData?.map((item) => { + return ( +
+

+ {item.pinned && t('pinnedAnnouncement')}{' '} + + {item.content} + +

+
+ popupRef.current?.open(item)} + > + {t('viewDetails')} + +
+
+ ); + })} +
+
+ + ) : ( + + )}
diff --git a/apps/user/app/(main)/(content)/(user)/document/tutorial-button.tsx b/apps/user/app/(main)/(content)/(user)/document/tutorial-button.tsx index 7d99800..d4a8a15 100644 --- a/apps/user/app/(main)/(content)/(user)/document/tutorial-button.tsx +++ b/apps/user/app/(main)/(content)/(user)/document/tutorial-button.tsx @@ -155,7 +155,7 @@ export function TutorialButton({ items }: { items: Item[] }) { buttonVariants({ variant: 'secondary', }), - 'rounded-full border-[#A8D4ED] bg-[#A8D4ED] px-[35px] py-[9px] text-center text-xs font-bold text-white hover:bg-[#225BA9] hover:text-white sm:min-w-[150px] sm:text-xl', + 'rounded-full border-[#A8D4ED] bg-[#A8D4ED] px-[35px] py-[9px] text-center text-xs font-bold text-white hover:bg-[#225BA9] hover:text-white sm:min-w-[100px]', )} > {t('read')} diff --git a/apps/user/components/affiliate/index.tsx b/apps/user/components/affiliate/index.tsx index 389db38..44e87ed 100644 --- a/apps/user/components/affiliate/index.tsx +++ b/apps/user/components/affiliate/index.tsx @@ -5,14 +5,15 @@ import { AffiliateDialogRef, } from '@/components/affiliate/components/AffiliateDialog'; import { Display } from '@/components/display'; -import { Empty } from '@/components/empty'; import SvgIcon from '@/components/SvgIcon'; import useGlobalStore from '@/config/use-global'; +import { querySubscribeList } from '@/services/user/subscribe'; import { queryUserAffiliate, queryUserAffiliateList } from '@/services/user/user'; import { useQuery } from '@tanstack/react-query'; import { Button } from '@workspace/airo-ui/components/button'; import { Card, CardContent } from '@workspace/airo-ui/components/card'; import { Input } from '@workspace/airo-ui/components/input'; +import { default as Airo_Empty } from '@workspace/airo-ui/custom-components/empty'; import { formatDate } from '@workspace/airo-ui/utils'; import { useTranslations } from 'next-intl'; import { useRef, useState } from 'react'; @@ -31,16 +32,26 @@ export default function Affiliate() { }, }); - const { data: inviteList = [] } = useQuery({ + const { data: inviteListData } = useQuery({ queryKey: ['queryUserAffiliateList'], queryFn: async () => { const response = await queryUserAffiliateList({ page: 1, size: 3, }); - return response.data.data?.list || []; + return response.data.data; }, }); + + const { data: proPlan } = useQuery({ + queryKey: ['querySubscribeList1'], + queryFn: async () => { + const { data } = await querySubscribeList(); + const list = data.data?.list?.filter((v) => v.unit_time === 'Month') || []; + return list.find((v) => v.name.includes('Pro')); + }, + }); + const dialogRef = useRef(null); return (
@@ -54,8 +65,13 @@ export default function Affiliate() {
{t('totalCommission')}
{t('commissionInfo')}
-
+
{t('historicalRecommendedUsers')} + {inviteListData?.total}
@@ -121,14 +137,14 @@ export default function Affiliate() {
- {inviteList?.length ? ( + {inviteListData?.list?.length ? (
- {inviteList?.map((invite) => { + {inviteListData?.list?.map((invite) => { return (
@@ -146,7 +162,7 @@ export default function Affiliate() { })}
) : ( - + )}
@@ -160,146 +176,149 @@ export default function Affiliate() { {t('commissionCalculationInfo')}
- {(() => { - // Pro plan: $60/month, $576/year - const MONTHLY_PRICE = 60; - const YEARLY_PRICE = 576; +
+ {(() => { + // Pro plan: $60/month, $576/year + const MONTHLY_PRICE = proPlan?.unit_price; + const discountItem = proPlan?.discount?.find((v) => v.quantity === 12); + const YEARLY_PRICE = proPlan?.unit_price * ((discountItem?.discount || 100) / 100) * 12; - const [count, setCount] = useState(10); - const clamp = (n: number) => Math.max(0, Math.min(10000, Math.floor(n))); + const [count, setCount] = useState(10); + const clamp = (n: number) => Math.max(0, Math.min(10000, Math.floor(n))); - const firstMonth = count * MONTHLY_PRICE * 0.5; // 50% - const firstYear = count * YEARLY_PRICE * 0.3; // 30% - const recurMonth = count * MONTHLY_PRICE * 0.2; // 20% - const recurYear = count * YEARLY_PRICE * 0.2; // 20% + const firstMonth = count * MONTHLY_PRICE * 0.5; // 50% + const firstYear = count * YEARLY_PRICE * 0.3; // 30% + const recurMonth = count * MONTHLY_PRICE * 0.2; // 20% + const recurYear = count * YEARLY_PRICE * 0.2; // 20% - return ( -
- {/* Calculator panel container */} -
- {/* Left: row headers (Monthly Plan / Yearly Plan) */} -
-
-
- {t('monthlyPackage')} + return ( +
+ {/* Calculator panel container */} +
+ {/* Left: row headers (Monthly Plan / Yearly Plan) */} +
+
+
+ {t('monthlyPackage')} +
+
+ {t('annualPackage')} +
-
- {t('annualPackage')} + + {/* Middle: First-time top-up users (double rounded corners + three rows) */} +
+
+
+
+
+
+
+ {t('firstTimeTopUpUser')} +
+
+ +
+
+
+ 50% +
+
+ up to{' '} + + + +
+
+
+
+
+
+ 30% +
+
+ up to{' '} + + + +
+
+
+
+
+ {/* Blue shadow block */} +
+
+ + {/* Right: Repeat top-up users (gray card + three rows) */} +
+
+ {t('repeatTopUpUser')} +
+ +
+
+ 20% +
+
+ up to{' '} + + + {' '} + {t('perMonth')} +
+
+ +
+
+ 20% +
+
+ up to{' '} + + + {' '} + {t('perYear')} +
+
- - {/* Middle: First-time top-up users (double rounded corners + three rows) */} -
-
-
-
-
-
-
- {t('firstTimeTopUpUser')} -
-
- -
-
-
- 50% -
-
- up to{' '} - - - -
-
-
-
-
-
- 30% -
-
- up to{' '} - - - -
-
-
-
-
- {/* Blue shadow block */} -
-
- - {/* Right: Repeat top-up users (gray card + three rows) */} -
-
- {t('repeatTopUpUser')} -
- -
-
- 20% -
-
- up to{' '} - - - {' '} - {t('perMonth')} -
-
- -
-
- 20% -
-
- up to{' '} - - - {' '} - {t('perYear')} -
+ {/* User count adjustment */} +
+ +
+ setCount(clamp(Number(e.target.value) || 0))} + 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` }} + /> + users
+
- {/* User count adjustment */} -
- -
- setCount(clamp(Number(e.target.value) || 0))} - 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` }} - /> - users -
- -
-
- ); - })()} + ); + })()} +
diff --git a/apps/user/components/empty.tsx b/apps/user/components/empty.tsx index 08f3a19..a7c395f 100644 --- a/apps/user/components/empty.tsx +++ b/apps/user/components/empty.tsx @@ -4,7 +4,7 @@ import { default as _Empty } from '@workspace/airo-ui/custom-components/empty'; import { useTranslations } from 'next-intl'; import { useEffect, useState } from 'react'; -export function Empty() { +export function Empty({ className }: { className?: string }) { const t = useTranslations('common'); const [description, setDescription] = useState(''); @@ -14,5 +14,5 @@ export function Empty() { setDescription(t(`empty.${random}`)); }, [t]); - return <_Empty description={description} />; + return <_Empty description={description} className={className} />; } diff --git a/apps/user/locales/en-US/affiliate.json b/apps/user/locales/en-US/affiliate.json index 8144cb8..faea8d0 100644 --- a/apps/user/locales/en-US/affiliate.json +++ b/apps/user/locales/en-US/affiliate.json @@ -8,11 +8,12 @@ "copyInviteLink": "Copy Invite Link", "copySuccess": "Copied Successfully", "firstTimeTopUpUser": "First-time Top-up User", - "historicalRecommendedUsers": "Historical Recommended Users: 7", + "historicalRecommendedUsers": "Historical Recommended Users: ", "inviteCode": "Invite Code", "inviteRecords": "Invite Records", "monthlyPackage": "Monthly Package", "more": "More", + "noInvitationRecords": "No Invitation Records", "perMonth": "/ Month", "perYear": "/ Year", "registrationTime": "Registration Time", diff --git a/apps/user/locales/zh-CN/affiliate.json b/apps/user/locales/zh-CN/affiliate.json index 719331e..0691a68 100644 --- a/apps/user/locales/zh-CN/affiliate.json +++ b/apps/user/locales/zh-CN/affiliate.json @@ -8,11 +8,12 @@ "copyInviteLink": "复制邀请链接", "copySuccess": "复制成功", "firstTimeTopUpUser": "首充用户", - "historicalRecommendedUsers": "历史推荐用户:7", + "historicalRecommendedUsers": "历史推荐用户:", "inviteCode": "邀请码", "inviteRecords": "邀请记录", "monthlyPackage": "月付套餐", "more": "更多", + "noInvitationRecords": "暂无邀请记录", "perMonth": "/ 月", "perYear": "/ 年", "registrationTime": "注册时间", diff --git a/packages/airo-ui/src/custom-components/empty.tsx b/packages/airo-ui/src/custom-components/empty.tsx index 83c9700..17eabb7 100644 --- a/packages/airo-ui/src/custom-components/empty.tsx +++ b/packages/airo-ui/src/custom-components/empty.tsx @@ -1,6 +1,14 @@ -export default function Empty({ description }: { description?: React.ReactNode }) { +import { cn } from '@workspace/airo-ui/lib/utils'; + +export default function Empty({ + className, + description, +}: { + description?: React.ReactNode; + className?: string; +}) { return ( -
+