import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { Box, LinearProgress, Skeleton, Typography } from '@mui/material';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Check } from '@mui/icons-material';
export function VendorPlaceholder() {
return (
);
}
interface VendorStatus {
success: boolean;
name?: string;
key?: string;
status: 'delivered' | 'pending' | 'failed';
progress: number;
message: string;
appUrl?: string;
title?: string;
vendorType: string;
}
const getVendorLabel = (vendor: VendorStatus, isFailed: boolean, t: any) => {
const name = vendor.name || vendor.title;
const isCompleted = vendor.status === 'delivered';
if (vendor.vendorType === 'didnames') {
if (isFailed) {
return t('payment.checkout.vendor.didnames.failed', { name });
}
if (isCompleted) {
return t('payment.checkout.vendor.didnames.completed', { name });
}
return t('payment.checkout.vendor.didnames.processing', { name });
}
// Default to launcher type
if (isFailed) {
return t('payment.checkout.vendor.launcher.failed', { name });
}
if (isCompleted) {
return t('payment.checkout.vendor.launcher.completed', { name });
}
return t('payment.checkout.vendor.launcher.processing', { name });
};
export function VendorProgressItem({ vendor }: { vendor: VendorStatus }) {
const { t } = useLocaleContext();
const [displayProgress, setDisplayProgress] = useState(0);
const animationRef = useRef();
const startAnimation = useCallback(() => {
const realProgress = vendor.progress || 0;
let startTime: number;
let startProgress: number;
const animate = (currentTime: number) => {
if (!startTime) {
startTime = currentTime;
startProgress = displayProgress;
}
const elapsed = currentTime - startTime;
let newProgress: number;
if (realProgress === 100) {
// If progress is 100%, set directly to 100% without animation
newProgress = 100;
} else if (realProgress === 0) {
// When no data available, increase 1% per second
newProgress = Math.min(startProgress + elapsed / 1000, 99);
} else if (realProgress > startProgress) {
const duration = 1000; // 1 second to reach target quickly
const progress = Math.min(elapsed / duration, 1);
newProgress = startProgress + (realProgress - startProgress) * progress;
} else {
// After reaching target, increase 1% per second, max 99%
newProgress = Math.min(startProgress + elapsed / 1000, 99);
}
// Ensure progress is an integer
newProgress = Math.round(newProgress);
setDisplayProgress((pre) => Math.min(pre > newProgress ? pre : newProgress, 100));
// Stop animation immediately when 100%
if (realProgress === 100) {
return;
}
// Continue animation in other cases
if (newProgress < 99 && realProgress < 100) {
animationRef.current = requestAnimationFrame(animate);
}
};
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
animationRef.current = requestAnimationFrame(animate);
}, [vendor.progress, displayProgress]);
useEffect(() => {
startAnimation();
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
};
}, [startAnimation]);
const isCompleted = displayProgress >= 100;
const isFailed = vendor.status === 'failed';
const nameText = getVendorLabel(vendor, isFailed, t);
// 如果是失败状态,显示错误 UI
if (isFailed) {
return (
{nameText}
{t('payment.checkout.vendor.progress', { progress: 0 })}
);
}
if (!vendor.name && !vendor.title) {
return ;
}
return (
{nameText} {isCompleted ? : null}
{isCompleted ? null : (
{t('payment.checkout.vendor.progress', { progress: displayProgress })}
)}
);
}