167 lines
5.2 KiB
TypeScript
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;
|