import { useEffect, useState } from 'react'; import { EventsOn } from '../../wailsjs/runtime/runtime'; import { Eye, EyeRed, EyeSlash, Gear, Heart, Play, Pause, Star, ThumbsDown, ThumbsUp, ChessRook, } from '../assets'; import './PageDetails.css'; import { ActivateAccount, ActivateChannel, DeleteAccount, DeleteChannel, Login, Logout, UpdateAccountApi, UpdateChannelApi, } from '../../wailsjs/go/main/App'; import { Modal, SmallModal } from './Modal'; function countString(value) { switch (true) { case value <= 0 || value == undefined: return '0'; case value < 1000: return value; case value < 1000000: return (value / 1000).toFixed(3).slice(0, -2) + 'K'; case value < 1000000000: return (value / 1000000).toFixed(6).slice(0, -5) + 'M'; default: return 'Inf'; } } function PageDetails(props) { const [activate, setActivate] = useState(false); const [active, setActive] = useState(false); const [activity, setActivity] = useState(null); const [openApi, setOpenApi] = useState(false); const [apiValid, setApiValid] = useState(true); const [editingApi, setEditingApi] = useState(false); const [editApi, setEditApi] = useState(''); const updateEditApi = (event) => { setEditApi(event.target.value); }; const [openDelete, setOpenDelete] = useState(false); const [deleting, setDeleting] = useState(false); const [deleteName, setDeleteName] = useState(''); const updateDeleteName = (event) => { if (deleting) { return; } setDeleteName(event.target.value); }; const [details, setDetails] = useState(null); const [error, setError] = useState(''); const [live, setLive] = useState(false); const [liveTitle, setLiveTitle] = useState(''); const [openLogin, setOpenLogin] = useState(false); const [loggingIn, setLoggingIn] = useState(false); const [loginUsername, setLoginUsername] = useState(''); const updateLoginUsername = (event) => { if (loggingIn) { return; } setLoginUsername(event.target.value); }; const [loginUsernameValid, setLoginUsernameValid] = useState(true); const [loginPassword, setLoginPassword] = useState(''); const updateLoginPassword = (event) => { if (loggingIn) { return; } setLoginPassword(event.target.value); }; const [loginPasswordValid, setLoginPasswordValid] = useState(true); const [openLogout, setOpenLogout] = useState(false); const [loggingOut, setLoggingOut] = useState(false); const [settings, setSettings] = useState(false); const triggerSettings = () => setSettings(!settings); useEffect(() => { EventsOn('PageDetails', (event) => { setDetails(event); // TODO: do I need to reset all editing/logging out/etc. values? }); EventsOn('PageActivity', (event) => { setActivity(event); setActive(true); if (event.livestreams.length > 0) { setLive(true); } else { setLive(false); } }); EventsOn('PageActive', (event) => { if (event) { setActive(true); } else { setActive(false); setActivity(null); setLive(false); } }); }, []); useEffect(() => { if (deleting) { switch (true) { case details.type === 'Channel': DeleteChannel(details.id) .then(() => resetDelete()) .catch((error) => { setDeleting(false); setError(error); }); return; case details.type === 'Account': DeleteAccount(details.id) .then(() => resetDelete()) .catch((error) => { setDeleting(false); setError(error); }); return; } } }, [deleting]); useEffect(() => { if (editingApi) { switch (true) { case details.type === 'Channel': UpdateChannelApi(details.id, editApi) .then(() => resetEditApi()) .catch((error) => { setEditingApi(false); setError(error); }); return; case details.type === 'Account': UpdateAccountApi(details.id, editApi) .then(() => resetEditApi()) .catch((error) => { setEditingApi(false); setError(error); }); return; } } }, [editingApi]); useEffect(() => { if (loggingIn && details.type === 'Account') { Login(loginUsername, loginPassword) .then(() => { resetLogin(); }) .catch((error) => { setLoggingIn(false); setError(error); }); } else if (loggingIn && details.type === 'Channel') { resetLogin(); } }, [loggingIn]); useEffect(() => { if (loggingOut && details.type === 'Account') { Logout(details.id) .catch((error) => { setError(error); }) .finally(() => resetLogout()); } else if (loggingOut && details.type === 'Channel') { resetLogout(); } }, [loggingOut]); const activatePage = () => { switch (true) { case details.type === 'Channel': ActivateChannel(details.id).catch((error) => { setError(error); }); return; case details.type === 'Account': ActivateAccount(details.id).catch((error) => { setError(error); }); return; } }; const deletePage = () => { if (deleting || details.title !== deleteName) { return; } setDeleting(true); }; const resetDelete = () => { setDeleteName(''); setDeleting(false); setOpenDelete(false); }; const submitEditApi = () => { if (editingApi) { return; } if (editApi === '') { setApiValid(false); return; } setEditingApi(true); }; const closeEditApi = () => { if (editingApi) { return; } resetEditApi(); }; const resetEditApi = () => { setOpenApi(false); setApiValid(true); setEditApi(''); setEditingApi(false); }; const login = () => { if (loginUsername === '') { setLoginUsernameValid(false); return; } if (loginPassword === '') { setLoginPasswordValid(false); return; } setLoggingIn(true); }; const closeLogin = () => { if (loggingIn) { return; } setOpenLogin(false); }; const resetLogin = () => { setLoggingIn(false); setOpenLogin(false); }; const logout = () => { setLoggingOut(true); }; const closeLogout = () => { if (loggingOut) { return; } setOpenLogout(false); }; const resetLogout = () => { setLoggingOut(false); setOpenLogout(false); }; return ( <> {openLogin && ( )} {openLogout && ( )} {error !== '' && ( setError('')} show={error !== ''} style={{ minWidth: '300px', maxWidth: '200px', maxHeight: '200px' }} title={'Error'} message={error} submitButton={'OK'} onSubmit={() => setError('')} /> )} {openDelete && (
Delete page Are you sure you want to delete {details.title}? This cannot be undone. You must type '{details.title}' into the box to delete.
)} {openApi && ( )}
{details !== null && ( <>
{details.title} {details.type}
{details.has_api && ( )}
{settings && ( <>
{details.type === 'Account' && ( )}
)} {active && activity !== null && ( <> {live && ( )} )} {!active && (
{details.has_api ? 'Press play to start API' : 'Open settings to add API key'}
)} )}
); } export default PageDetails; function PageActivity(props) { const eventDate = (event) => { if (event.followed_on) { return event.followed_on; } if (event.subscribed_on) { return event.subscribed_on; } }; const sortEvents = () => { let sorted = [ ...props.activity.followers.recent_followers, ...props.activity.subscribers.recent_subscribers, ].sort((a, b) => (eventDate(a) < eventDate(b) ? 1 : -1)); return sorted; }; return ( <>
Followers: {countString(props.activity.followers.num_followers)}
Subscribers: {countString(props.activity.subscribers.num_subscribers)}
{sortEvents().map((event, index) => ( ))}
); } function PageEvent(props) { const dateDate = (date) => { const options = { month: 'short' }; let month = new Intl.DateTimeFormat('en-US', options).format(date); let day = date.getDate(); return month + ' ' + day; }; const dateDay = (date) => { let now = new Date(); let today = now.getDay(); switch (date.getDay()) { case 0: return 'Sunday'; case 1: return 'Monday'; case 2: return 'Tuesday'; case 3: return 'Wednesday'; case 4: return 'Thursday'; case 5: return 'Friday'; case 6: return 'Saturday'; } }; const dateTime = (date) => { let now = new Date(); let today = now.getDay(); let day = date.getDay(); if (today !== day) { return dateDay(date); } let hours24 = date.getHours(); let hours = hours24 % 12 || 12; let minutes = date.getMinutes(); if (minutes < 10) { minutes = '0' + minutes; } let mer = 'pm'; if (hours24 < 12) { mer = 'am'; } return hours + ':' + minutes + ' ' + mer; }; const dateString = (d) => { if (isNaN(Date.parse(d))) { return 'Who knows?'; } let now = new Date(); let date = new Date(d); // Fix Rumble's timezone problem date.setHours(date.getHours() - 4); let diff = now - date; switch (true) { case diff < 0: return 'In the future!?'; case diff < 60000: return 'Now'; case diff < 3600000: let minutes = Math.floor(diff / 1000 / 60); let postfix = ' mins ago'; if (minutes == 1) { postfix = ' min ago'; } return minutes + postfix; case diff < 86400000: return dateTime(date); case diff < 604800000: return dateDay(date); default: return dateDate(date); } }; return (
{props.event.followed_on && } {props.event.subscribed_on && ( )}
{props.event.username} {props.event.followed_on && 'Followed you'} {props.event.subscribed_on && 'Subscribed'}
{props.event.followed_on && dateString(props.event.followed_on)} {props.event.subscribed_on && dateString(props.event.subscribed_on)}
); } function DetailsFooter(props) { return (
{props.title}
{countString(props.viewers)}
{countString(props.likes)}
{countString(props.dislikes)}
{props.categories.primary.title} {props.categories.secondary.title}
); } function ModalEditApi(props) { const [showKey, setShowKey] = useState(false); const updateShowKey = () => setShowKey(!showKey); return (
Edit API Key Enter new API key below
{props.apiValid === false ? ( ) : ( )}
API KEYS SHOULD LOOK LIKE https://rumble.com/-livestream-api/get-data?key=really-long_string-of_random-characters
); } function ModalLogin(props) { const [showPassword, setShowPassword] = useState(false); const updateShowPassword = () => setShowPassword(!showPassword); return (
Login Log into your Rumble account
{props.usernameValid === false ? ( ) : ( )}
{props.passwordValid === false ? ( ) : ( )}
); }