feat: 修改样式
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
import { Display } from '@/components/display';
|
||||
import Renewal from '@/components/subscribe/renewal';
|
||||
import { resetUserSubscribeToken } from '@/services/user/user';
|
||||
import { Button } from '@workspace/airo-ui/components/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@workspace/airo-ui/components/select';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import SvgIcon from '@/components/SvgIcon';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} 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 { differenceInDays } from '@workspace/airo-ui/utils';
|
||||
import { QRCodeCanvas } from 'qrcode.react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
interface SubscribeCardProps {
|
||||
userSubscribeData: API.UserSubscribe;
|
||||
protocol: string[];
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
const SubscribeCard = (props: SubscribeCardProps) => {
|
||||
const t = useTranslations('dashboard');
|
||||
const { userSubscribeData } = props;
|
||||
|
||||
const { getUserSubscribe } = useGlobalStore();
|
||||
|
||||
const [protocol, setProtocol] = useState('');
|
||||
const [userSubscribeProtocol, setUserSubscribeProtocol] = useState<string[]>([]);
|
||||
const [userSubscribeProtocolCurrent, setUserSubscribeProtocolCurrent] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
const list = getUserSubscribe(userSubscribeData.token, protocol);
|
||||
setUserSubscribeProtocol(list);
|
||||
if (list.length > 0) {
|
||||
setUserSubscribeProtocolCurrent(0);
|
||||
}
|
||||
}, [props.userSubscribeData.token, protocol]);
|
||||
|
||||
return (
|
||||
<div className='space-y-2 sm:space-y-4'>
|
||||
<p className='text-xs font-light text-[#666666] sm:text-sm sm:font-normal'>
|
||||
{t('copySubscriptionLinkOrScanQrCode')}
|
||||
</p>
|
||||
|
||||
{/* 统计信息 */}
|
||||
<div className='rounded-[20px] bg-[#EAEAEA] p-4'>
|
||||
<div className='grid grid-cols-3 gap-4 text-center'>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
{t('totalTraffic')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
<Display
|
||||
type='traffic'
|
||||
value={userSubscribeData.traffic}
|
||||
unlimited={!userSubscribeData.traffic}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
{t('nextResetDays')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
{userSubscribeData.reset_time
|
||||
? differenceInDays(new Date(userSubscribeData.reset_time), new Date())
|
||||
: t('noReset')}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-[10px] text-[rgba(132,132,132,0.7)] sm:text-xs'>
|
||||
{t('expirationDays')}
|
||||
</p>
|
||||
<p className='text-xs font-medium text-[#0F2C53] sm:text-lg'>
|
||||
{userSubscribeData.expire_time
|
||||
? differenceInDays(new Date(userSubscribeData.expire_time), new Date()) ||
|
||||
t('unknown')
|
||||
: t('noLimit')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 订阅链接 */}
|
||||
<div className='rounded-[26px] bg-[#EAEAEA] p-2 sm:p-4'>
|
||||
<div className='mb-3 flex flex-wrap justify-between gap-4'>
|
||||
{props.protocol.length > 1 && (
|
||||
<Tabs
|
||||
value={protocol}
|
||||
onValueChange={setProtocol}
|
||||
className='w-full max-w-full md:w-auto'
|
||||
>
|
||||
<TabsList className='flex h-full flex-wrap gap-2 bg-transparent p-0'>
|
||||
{['all', ...(props.protocol || [])].map((item) => (
|
||||
<TabsTrigger
|
||||
value={item === 'all' ? '' : item}
|
||||
key={item}
|
||||
className='rounded-full bg-[#EAEAEA] px-6 py-1 text-[10px] uppercase text-[#66666673] shadow-[inset_0px_0px_4px_0px_rgba(0,0,0,0.25)] data-[state=active]:bg-[#225BA9] data-[state=active]:text-white'
|
||||
>
|
||||
{item}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
)}
|
||||
</div>
|
||||
<div className={'mb-3 flex items-center justify-center gap-1'}>
|
||||
<div
|
||||
className={
|
||||
'flex flex-1 items-center gap-1 rounded-full bg-[#BABABA] pl-1 sm:gap-2 sm:rounded-[16px] sm:pl-2'
|
||||
}
|
||||
>
|
||||
<Select
|
||||
value={userSubscribeProtocolCurrent}
|
||||
onValueChange={setUserSubscribeProtocolCurrent}
|
||||
>
|
||||
<SelectTrigger className='h-auto w-auto flex-shrink-0 rounded-[16px] border-none bg-[#D9D9D9] px-2.5 py-0.5 text-[13px] text-sm font-medium text-white shadow-none hover:bg-[#848484] focus:ring-0 sm:h-[35px] sm:rounded-[8px] sm:p-2 [&>svg]:hidden'>
|
||||
<SelectValue>
|
||||
<div className='flex flex-col items-center justify-center text-[10px] sm:text-sm'>
|
||||
<div>
|
||||
{t('subscriptionUrl')}
|
||||
{userSubscribeProtocolCurrent + 1}
|
||||
</div>
|
||||
<div className='-mt-0.5 h-0 w-0 scale-50 border-l-[5px] border-r-[5px] border-t-[5px] border-l-transparent border-r-transparent border-t-white sm:scale-100'></div>
|
||||
</div>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{userSubscribeProtocol.map((url, index) => (
|
||||
<SelectItem
|
||||
key={index}
|
||||
value={index}
|
||||
className={'focus:text-accent-foreground bg-[#D9D9D9] focus:bg-[#A8D4ED]'}
|
||||
>
|
||||
{t('subscriptionUrl')}
|
||||
{index + 1}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<div className='flex-1 rounded-full bg-white px-3 py-1 text-[10px] leading-tight text-[#225BA9] shadow-[inset_0px_0px_7.6px_0px_rgba(0,0,0,0.25)] sm:rounded-[16px] sm:text-xs'>
|
||||
<div className={'flex items-center gap-4 py-1 text-[10px] sm:text-[16px]'}>
|
||||
<div className={'line-clamp-2 flex-1 break-all'}>
|
||||
{userSubscribeProtocol[userSubscribeProtocolCurrent]}
|
||||
</div>
|
||||
<CopyToClipboard
|
||||
text={userSubscribeProtocol[userSubscribeProtocolCurrent]}
|
||||
onCopy={(text, result) => {
|
||||
if (result) {
|
||||
toast.success(t('copySuccess'));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className={'cursor-pointer p-1'}>
|
||||
<SvgIcon name={'copy'}></SvgIcon>
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<div className={'size-10'}>
|
||||
<SvgIcon name={'qrcode'} width={'100%'} height={'100%'}></SvgIcon>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className='w-auto rounded-xl p-4' align='end'>
|
||||
<div className='flex flex-col items-center gap-2'>
|
||||
<p className='text-muted-foreground text-center text-xs'>
|
||||
{t('scanCodeToSubscribe')}
|
||||
</p>
|
||||
<QRCodeCanvas
|
||||
value={userSubscribeProtocol[userSubscribeProtocolCurrent]}
|
||||
size={120}
|
||||
bgColor='transparent'
|
||||
fgColor='rgb(34, 91, 169)'
|
||||
/>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className='flex justify-between gap-2'>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
size='sm'
|
||||
className={
|
||||
'h-fit rounded-full bg-[#E22C2E] px-3 py-1 text-[10px] text-white sm:h-9 sm:text-xs'
|
||||
}
|
||||
variant='destructive'
|
||||
>
|
||||
{t('resetSubscription')}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{t('prompt')}</AlertDialogTitle>
|
||||
<AlertDialogDescription>{t('confirmResetSubscription')}</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={async () => {
|
||||
await resetUserSubscribeToken({
|
||||
user_subscribe_id: userSubscribeData.id || 0,
|
||||
});
|
||||
await props.refetch();
|
||||
toast.success(t('resetSuccess'));
|
||||
}}
|
||||
>
|
||||
{t('confirm')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<Renewal
|
||||
className='h-fit rounded-full bg-[#A8D4ED] px-3 py-1 text-[10px] text-white sm:h-9 sm:text-xs'
|
||||
id={userSubscribeData.id}
|
||||
subscribe={userSubscribeData.subscribe}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubscribeCard;
|
||||
Reference in New Issue
Block a user