UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

443 lines (435 loc) 20 kB
import React, { useState, useEffect } from 'react'; import { DEFAULT_EPG_THEME } from '../types/EPGTypes.js'; import { formatDateTime, getProgramDuration, isProgramLive, getProgramProgress } from '../utils/EPGUtils.js'; export const EPGProgramDetails = ({ program, channel, onClose, onAction, isModal = false, currentTime = Date.now(), className = '', style = {}, config, theme: themeProp, }) => { const theme = { ...DEFAULT_EPG_THEME, ...themeProp }; const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const showFavoriteButton = config?.showFavoriteButton ?? false; const showRecordButton = config?.showRecordButton ?? false; const showReminderButton = config?.showReminderButton ?? false; const showCatchupButton = config?.showCatchupButton ?? false; useEffect(() => { setError(null); }, [program]); if (!program) return null; const duration = getProgramDuration(program); const isLive = isProgramLive(program, currentTime); const progress = isLive ? getProgramProgress(program, currentTime) : 0; const hasEnded = new Date(program.till).getTime() < currentTime; const handleAction = async (actionType) => { if (!channel || isLoading) return; setIsLoading(true); setError(null); try { await onAction({ type: actionType, program, channel, }); } catch (err) { setError(err instanceof Error ? err.message : 'Action failed. Please try again.'); } finally { setIsLoading(false); } }; const handleOverlayClick = (e) => { if (e.target === e.currentTarget && isModal) { onClose(); } }; const detailsContent = (React.createElement("div", { className: `epg-program-details ${isModal ? 'modal' : 'panel'} ${className}`, style: { backgroundColor: '#1a1a1a', border: '1px solid #333', borderRadius: isModal ? '12px' : '8px', overflow: 'hidden', boxShadow: '0 8px 24px rgba(0,0,0,0.4)', maxWidth: isModal ? '600px' : '100%', maxHeight: isModal ? '85vh' : '70vh', display: 'flex', flexDirection: 'column', ...style, } }, React.createElement("div", { className: "epg-details-header", style: { display: 'flex', alignItems: 'flex-start', padding: '20px', borderBottom: '1px solid #333', position: 'relative', flexShrink: 0, } }, program.image && (React.createElement("div", { style: { width: '120px', height: '68px', borderRadius: '8px', overflow: 'hidden', marginRight: '16px', flexShrink: 0, position: 'relative', } }, React.createElement("img", { src: program.image, alt: program.title, style: { width: '100%', height: '100%', objectFit: 'cover', }, onError: (e) => { e.currentTarget.style.display = 'none'; } }), isLive && (React.createElement("div", { style: { position: 'absolute', top: '4px', right: '4px', backgroundColor: theme.primaryColor, color: '#fff', fontSize: '10px', fontWeight: '700', padding: '2px 6px', borderRadius: '4px', } }, "LIVE")))), React.createElement("div", { style: { flex: 1, minWidth: 0 } }, React.createElement("h2", { style: { color: '#fff', fontSize: '20px', fontWeight: '700', lineHeight: '1.3', margin: '0 0 8px 0', } }, program.title), channel && (React.createElement("div", { style: { color: '#888', fontSize: '14px', fontWeight: '500', marginBottom: '8px', } }, channel.programTitle)), React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '16px', marginBottom: '8px', flexWrap: 'wrap', } }, React.createElement("div", { style: { color: '#fff', fontSize: '14px', fontWeight: '600', } }, formatDateTime(new Date(program.since).getTime())), React.createElement("div", { style: { color: '#888', fontSize: '13px', } }, duration, " min", duration !== 1 ? 's' : ''), program.category && (React.createElement("div", { style: { backgroundColor: '#333', color: '#fff', fontSize: '11px', fontWeight: '600', padding: '2px 8px', borderRadius: '12px', } }, program.category)), program.rating && (React.createElement("div", { style: { backgroundColor: 'theme.primaryColor', color: '#fff', fontSize: '11px', fontWeight: '700', padding: '2px 8px', borderRadius: '4px', } }, program.rating))), isLive && (React.createElement("div", { style: { marginTop: '8px', marginBottom: '8px', } }, React.createElement("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '4px', } }, React.createElement("span", { style: { color: theme.primaryColor, fontSize: '12px', fontWeight: '600' } }, "LIVE NOW"), React.createElement("span", { style: { color: '#888', fontSize: '12px' } }, Math.round(progress), "% complete")), React.createElement("div", { style: { height: '4px', backgroundColor: '#333', borderRadius: '2px', overflow: 'hidden', } }, React.createElement("div", { style: { height: '100%', width: `${progress}%`, backgroundColor: theme.primaryColor, transition: 'width 0.3s ease', } }))))), React.createElement("button", { onClick: onClose, style: { position: 'absolute', top: '16px', right: '16px', width: '32px', height: '32px', borderRadius: '50%', border: 'none', backgroundColor: '#333', color: '#fff', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px', transition: 'background-color 0.2s ease', }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = '#444'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = '#333'; } }, "\u00D7")), React.createElement("div", { className: "epg-details-content", style: { padding: '20px', paddingRight: '16px', flex: 1, overflow: 'auto', minHeight: 0, scrollbarWidth: 'thin', scrollbarColor: '#444 #2a2a2a', } }, program.description && (React.createElement("div", { style: { marginBottom: '20px' } }, React.createElement("h3", { style: { color: '#fff', fontSize: '16px', fontWeight: '600', marginBottom: '8px', } }, "Description"), React.createElement("p", { style: { color: '#ccc', fontSize: '14px', lineHeight: '1.5', margin: 0, } }, program.description))), (program.isFavorite || program.isRecording || program.hasReminder || program.hasCatchup) && (React.createElement("div", { style: { marginBottom: '20px' } }, React.createElement("h3", { style: { color: '#fff', fontSize: '16px', fontWeight: '600', marginBottom: '8px', } }, "Status"), React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', gap: '8px', } }, program.isFavorite && (React.createElement("span", { style: { backgroundColor: 'theme.primaryColor', color: '#fff', fontSize: '12px', fontWeight: '600', padding: '4px 8px', borderRadius: '4px', } }, "\u2605 Favorite")), program.isRecording && (React.createElement("span", { style: { backgroundColor: '#e74c3c', color: '#fff', fontSize: '12px', fontWeight: '600', padding: '4px 8px', borderRadius: '4px', } }, "\u25CF Recording")), program.hasReminder && (React.createElement("span", { style: { backgroundColor: '#3498db', color: '#fff', fontSize: '12px', fontWeight: '600', padding: '4px 8px', borderRadius: '4px', } }, "\uD83D\uDD14 Reminder")), program.hasCatchup && (React.createElement("span", { style: { backgroundColor: '#2ecc71', color: '#fff', fontSize: '12px', fontWeight: '600', padding: '4px 8px', borderRadius: '4px', } }, "\u21BB Catchup"))))), error && (React.createElement("div", { style: { backgroundColor: '#e74c3c', color: '#fff', padding: '12px', borderRadius: '4px', marginBottom: '16px', fontSize: '14px', } }, error))), React.createElement("div", { className: "epg-details-actions", style: { padding: '20px', borderTop: '1px solid #333', display: 'flex', gap: '12px', flexWrap: 'wrap', flexShrink: 0, backgroundColor: '#1a1a1a', } }, showFavoriteButton && (React.createElement("button", { onClick: () => handleAction('favorite'), disabled: isLoading, style: { flex: '1 1 120px', height: '40px', borderRadius: '6px', border: 'none', backgroundColor: program.isFavorite ? 'theme.primaryColor' : '#333', color: '#fff', fontSize: '13px', fontWeight: '600', cursor: isLoading ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s ease', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px', }, onMouseEnter: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.isFavorite ? '#ff8555' : '#444'; } }, onMouseLeave: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.isFavorite ? 'theme.primaryColor' : '#333'; } } }, "\u2605 ", program.isFavorite ? 'Favorited' : 'Favorite')), showRecordButton && !hasEnded && (React.createElement("button", { onClick: () => handleAction('record'), disabled: isLoading, style: { flex: '1 1 120px', height: '40px', borderRadius: '6px', border: 'none', backgroundColor: program.isRecording ? '#e74c3c' : '#333', color: '#fff', fontSize: '13px', fontWeight: '600', cursor: isLoading ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s ease', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px', }, onMouseEnter: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.isRecording ? '#c0392b' : '#444'; } }, onMouseLeave: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.isRecording ? '#e74c3c' : '#333'; } } }, "\u25CF ", program.isRecording ? 'Recording' : 'Record')), showReminderButton && !isLive && !hasEnded && (React.createElement("button", { onClick: () => handleAction('reminder'), disabled: isLoading, style: { flex: '1 1 120px', height: '40px', borderRadius: '6px', border: 'none', backgroundColor: program.hasReminder ? '#3498db' : '#333', color: '#fff', fontSize: '13px', fontWeight: '600', cursor: isLoading ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s ease', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px', }, onMouseEnter: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.hasReminder ? '#2980b9' : '#444'; } }, onMouseLeave: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = program.hasReminder ? '#3498db' : '#333'; } } }, "\uD83D\uDD14 ", program.hasReminder ? 'Reminder Set' : 'Remind Me')), showCatchupButton && hasEnded && (React.createElement("button", { onClick: () => handleAction('catchup'), disabled: isLoading, style: { flex: '1 1 120px', height: '40px', borderRadius: '6px', border: 'none', backgroundColor: '#2ecc71', color: '#fff', fontSize: '13px', fontWeight: '600', cursor: isLoading ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s ease', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px', }, onMouseEnter: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = '#27ae60'; } }, onMouseLeave: (e) => { if (!isLoading) { e.currentTarget.style.backgroundColor = '#2ecc71'; } } }, "\u21BB Watch Catchup"))))); if (isModal) { return (React.createElement(React.Fragment, null, React.createElement("div", { className: "epg-modal-overlay", style: { position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0, 0, 0, 0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, padding: '20px', }, onClick: handleOverlayClick }, detailsContent), React.createElement("style", null, ` .epg-details-content::-webkit-scrollbar { width: 6px; } .epg-details-content::-webkit-scrollbar-track { background: #2a2a2a; border-radius: 3px; } .epg-details-content::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; transition: background 0.2s ease; } .epg-details-content::-webkit-scrollbar-thumb:hover { background: #555; } .epg-program-details { scrollbar-width: thin; scrollbar-color: #444 #2a2a2a; } `))); } return (React.createElement(React.Fragment, null, detailsContent, React.createElement("style", null, ` .epg-details-content::-webkit-scrollbar { width: 6px; } .epg-details-content::-webkit-scrollbar-track { background: #2a2a2a; border-radius: 3px; } .epg-details-content::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; transition: background 0.2s ease; } .epg-details-content::-webkit-scrollbar-thumb:hover { background: #555; } .epg-program-details { scrollbar-width: thin; scrollbar-color: #444 #2a2a2a; } `))); }; export default EPGProgramDetails; //# sourceMappingURL=EPGProgramDetails.js.map