o2o-castad-frontend/src/components/UploadProgressModal.tsx

167 lines
5.2 KiB
TypeScript

import React from 'react';
import { useTranslation } from 'react-i18next';
export type UploadStatus = 'pending' | 'uploading' | 'completed' | 'failed';
interface UploadProgressModalProps {
isOpen: boolean;
onClose: () => void;
status: UploadStatus;
progress: number;
videoTitle: string;
channelName: string;
youtubeUrl?: string;
errorMessage?: string;
isScheduled?: boolean;
}
const UploadProgressModal: React.FC<UploadProgressModalProps> = ({
isOpen,
onClose,
status,
progress,
videoTitle,
channelName,
youtubeUrl,
errorMessage,
isScheduled = false,
}) => {
const { t } = useTranslation();
if (!isOpen) return null;
const getStatusText = () => {
switch (status) {
case 'pending':
return t('upload.statusPending');
case 'uploading':
return t('upload.statusUploading');
case 'completed':
return isScheduled ? t('upload.statusScheduled') : t('upload.statusCompleted');
case 'failed':
return t('upload.statusFailed');
default:
return t('upload.statusDefault');
}
};
const getStatusIcon = () => {
switch (status) {
case 'pending':
case 'uploading':
return (
<div className="upload-progress-spinner">
<svg viewBox="0 0 50 50" className="upload-spinner-svg">
<circle cx="25" cy="25" r="20" fill="none" strokeWidth="4" />
</svg>
</div>
);
case 'completed':
return (
<div className="upload-progress-icon success">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<polyline points="20 6 9 17 4 12" />
</svg>
</div>
);
case 'failed':
return (
<div className="upload-progress-icon error">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</div>
);
default:
return null;
}
};
const canClose = status === 'completed' || status === 'failed';
return (
<div className="upload-progress-overlay">
<div className="upload-progress-modal">
{/* Header */}
<div className="upload-progress-header">
<h2 className="upload-progress-title">{isScheduled && status === 'completed' ? t('upload.titleScheduled') : t('upload.title')}</h2>
{canClose && (
<button className="upload-progress-close" onClick={onClose}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
)}
</div>
{/* Content */}
<div className="upload-progress-content">
{/* Status Icon */}
{getStatusIcon()}
{/* Status Text */}
<p className={`upload-progress-status ${status}`}>{getStatusText()}</p>
{/* Progress Bar (only for pending/uploading) */}
{(status === 'pending' || status === 'uploading') && (
<div className="upload-progress-bar-container">
<div
className="upload-progress-bar-fill"
style={{ width: `${progress}%` }}
/>
<span className="upload-progress-percent">{progress}%</span>
</div>
)}
{/* Video Info */}
<div className="upload-progress-info">
<div className="upload-progress-info-row">
<span className="upload-progress-label">{t('upload.videoTitleLabel')}</span>
<span className="upload-progress-value">{videoTitle}</span>
</div>
<div className="upload-progress-info-row">
<span className="upload-progress-label">{t('upload.channelLabel')}</span>
<span className="upload-progress-value">{channelName}</span>
</div>
</div>
{/* Error Message */}
{status === 'failed' && errorMessage && (
<div className="upload-progress-error">
<p>{errorMessage}</p>
</div>
)}
{/* Success: YouTube Link */}
{status === 'completed' && youtubeUrl && (
<a
href={youtubeUrl}
target="_blank"
rel="noopener noreferrer"
className="upload-progress-youtube-link"
>
<img src="/assets/images/social-youtube.png" alt="YouTube" className="upload-youtube-icon" />
{t('upload.viewOnYoutube')}
</a>
)}
</div>
{/* Footer */}
<div className="upload-progress-footer">
{canClose ? (
<button className="upload-progress-btn primary" onClick={onClose}>
{status === 'completed' ? t('upload.confirm') : t('upload.close')}
</button>
) : (
<p className="upload-progress-note">{t('upload.doNotClose')}</p>
)}
</div>
</div>
</div>
);
};
export default UploadProgressModal;