feature(ui) - events toggle and duration counter

This commit is contained in:
Shekar Siri 2021-07-05 12:22:17 +05:30
parent 5c0f321b00
commit eef908648b
13 changed files with 103 additions and 21 deletions

View file

@ -21,8 +21,11 @@ function AssistActions({ toggleChatWindow, userId, calling }: Props) {
const [ localStream, setLocalStream ] = useState<MediaStream | null>(null);
const [ endCall, setEndCall ] = useState<()=>void>(()=>{});
function onClose(stream) {
console.log("Closed")
useEffect(() => {
return endCall
}, [])
function onClose(stream) {
stream.getTracks().forEach(t=>t.stop());
}
function onReject() {

View file

@ -0,0 +1,7 @@
.wrapper {
background-color: rgba(255, 255, 255, 1);
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
padding: 5px;
box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.5);
}

View file

@ -0,0 +1,32 @@
import React from 'react'
import { Icon, Popup } from 'UI'
import { connectPlayer, toggleEvents } from 'Player';
import cn from 'classnames'
import stl from './EventsToggleButton.css'
function EventsToggleButton({ showEvents, toggleEvents }) {
return (
<Popup
trigger={
<button
className={cn("absolute right-0 z-50", stl.wrapper)}
onClick={toggleEvents}
>
<Icon
name={ showEvents ? 'chevron-double-right' : 'chevron-double-left' }
size="12"
/>
</button>
}
content={ showEvents ? 'Hide Events' : 'Show Events' }
size="tiny"
inverted
position="bottom right"
/>
)
}
export default connectPlayer(state => ({
showEvents: !state.showEvents
}), { toggleEvents })(EventsToggleButton)

View file

@ -0,0 +1 @@
export { default } from './EventsToggleButton'

View file

@ -8,13 +8,15 @@ import {
init as initPlayer,
clean as cleanPlayer,
} from 'Player';
import { Controls as PlayerControls } from 'Player';
import { Controls as PlayerControls, toggleEvents } from 'Player';
import cn from 'classnames'
import PlayerBlockHeader from '../Session_/PlayerBlockHeader';
import EventsBlock from '../Session_/EventsBlock';
import PlayerBlock from '../Session_/PlayerBlock';
import styles from '../Session_/session.css';
import EventsToggleButton from './EventsToggleButton';
@ -28,6 +30,19 @@ const InitLoader = connectPlayer(state => ({
loading: !state.initialized
}))(Loader);
const PlayerContentConnected = connectPlayer(state => ({
showEvents: !state.showEvents
}), { toggleEvents })(PlayerContent);
function PlayerContent({ live, fullscreen, showEvents, toggleEvents }) {
return (
<div className={ cn(styles.session, 'relative') } data-fullscreen={fullscreen}>
<PlayerBlock />
{ showEvents && !live && !fullscreen && <EventsBlockConnected player={PlayerControls}/> }
</div>
)
}
function WebPlayer ({ session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt }) {
useEffect(() => {
@ -44,10 +59,7 @@ function WebPlayer ({ session, toggleFullscreen, closeBottomBlock, live, fullscr
<PlayerProvider>
<InitLoader className="flex-1">
<PlayerBlockHeader fullscreen={fullscreen}/>
<div className={ styles.session } data-fullscreen={fullscreen}>
<PlayerBlock />
{ !live && !fullscreen && <EventsBlockConnected player={PlayerControls}/> }
</div>
<PlayerContentConnected fullscreen={fullscreen} live={live} />
</InitLoader>
</PlayerProvider>
);
@ -61,5 +73,5 @@ export default connect(state => ({
}), {
toggleFullscreen,
closeBottomBlock,
})(WebPlayer)
})(WebPlayer)

View file

@ -9,6 +9,7 @@ import { attach as attachPlayer, Controls as PlayerControls, connectPlayer } fro
import Controls from './Controls';
import stl from './player.css';
import AutoplayTimer from '../AutoplayTimer';
import EventsToggleButton from '../../Session/EventsToggleButton';
const ScreenWrapper = withOverlay()(React.memo(() => <div className={ stl.screenWrapper } />));
@ -20,7 +21,8 @@ const ScreenWrapper = withOverlay()(React.memo(() => <div className={ stl.screen
disabled: state.cssLoading || state.messagesLoading || state.inspectorMode,
removeOverlay: !state.messagesLoading && state.inspectorMode || state.live,
completed: state.completed,
autoplay: state.autoplay
autoplay: state.autoplay,
live: state.live
}))
@connect(state => ({
//session: state.getIn([ 'sessions', 'current' ]),
@ -105,6 +107,7 @@ export default class Player extends React.PureComponent {
completed,
autoplay,
nextId,
live,
} = this.props;
return (
@ -124,6 +127,7 @@ export default class Player extends React.PureComponent {
// label="Esc"
// />
}
{!live && !fullscreen && <EventsToggleButton /> }
<div className="relative flex-1">
{ !removeOverlay &&
<div

View file

@ -1,23 +1,26 @@
import React, { useState, useEffect } from 'react'
import { Duration } from 'luxon';
import { durationFormatted, formatTimeOrDate } from 'App/date';
interface Props {
startTime: any
}
function Counter({ startTime }: Props) {
const [count, setCount] = useState(0)
let intervalId;
const [duration, setDuration] = useState(new Date().getTime() - startTime)
useEffect(() => {
setInterval(function() {
setCount(count + 1000)
}, 1000)
}, [])
if (!intervalId) {
intervalId = setInterval(() => {
setDuration(duration + 1000)
}, 1000)
}
return () => clearInterval(intervalId)
}, [duration])
return (
<div className="mx-2">
{startTime && Duration.fromMillis(startTime + count).toFormat('m:ss')}
{startTime && Duration.fromMillis(duration).toFormat('m:ss')}
</div>
)
}

View file

@ -89,7 +89,9 @@ export default class SessionItem extends React.PureComponent {
</div>
</div>
<div className="flex flex-col items-center px-4" style={{ width: '150px'}}>
<div className="text-xl">{ formattedDuration }</div>
<div className="text-xl">
{ live ? <Counter startTime={startedAt} /> : formattedDuration }
</div>
<Label label="Duration" />
</div>
@ -109,8 +111,7 @@ export default class SessionItem extends React.PureComponent {
<Label label="Errors" color={errorsCount > 0 ? '' : 'color-gray-medium'} />
</div>
)}
{ live && <Counter startTime={startedAt} /> }
{ live && <LiveTag isLive={true} /> }
<div className={ cn(stl.iconDetails, 'px-4') }>

View file

@ -27,11 +27,13 @@ const SPEED_STORAGE_KEY = "__$player-speed$__";
const SKIP_STORAGE_KEY = "__$player-skip$__";
const SKIP_TO_ISSUE_STORAGE_KEY = "__$player-skip-to-issue$__";
const AUTOPLAY_STORAGE_KEY = "__$player-autoplay$__";
const SHOW_EVENTS_STORAGE_KEY = "__$player-show-events$__";
const storedSpeed: number = parseInt(localStorage.getItem(SPEED_STORAGE_KEY) || "") ;
const initialSpeed = [1,2,4,8,16].includes(storedSpeed) ? storedSpeed : 1;
const initialSkip = !!localStorage.getItem(SKIP_STORAGE_KEY);
const initialSkipToIssue = !!localStorage.getItem(SKIP_TO_ISSUE_STORAGE_KEY);
const initialAutoplay = !!localStorage.getItem(AUTOPLAY_STORAGE_KEY);
const initialShowEvents = !!localStorage.getItem(SHOW_EVENTS_STORAGE_KEY);
export const INITIAL_STATE: SuperState = {
...SUPER_INITIAL_STATE,
@ -50,6 +52,7 @@ export const INITIAL_NON_RESETABLE_STATE = {
skipToIssue: initialSkipToIssue,
autoplay: initialAutoplay,
speed: initialSpeed,
showEvents: initialShowEvents
}
export default class Player extends MessageDistributor {
@ -197,6 +200,12 @@ export default class Player extends MessageDistributor {
localStorage.setItem(AUTOPLAY_STORAGE_KEY, `${autoplay}`);
update({ autoplay });
}
toggleEvents() {
const showEvents = !getState().showEvents;
localStorage.setItem(SHOW_EVENTS_STORAGE_KEY, `${showEvents}`);
update({ showEvents });
}
_updateSpeed(speed: number) {
localStorage.setItem(SPEED_STORAGE_KEY, `${speed}`);

View file

@ -61,6 +61,7 @@ export const toggleSkip = initCheck((...args) => instance.toggleSkip(...args));
export const toggleSkipToIssue = initCheck((...args) => instance.toggleSkipToIssue(...args));
export const toggleAutoplay = initCheck((...args) => instance.toggleAutoplay(...args));
export const toggleSpeed = initCheck((...args) => instance.toggleSpeed(...args));
export const toggleEvents = initCheck((...args) => instance.toggleEvents(...args));
export const speedUp = initCheck((...args) => instance.speedUp(...args));
export const speedDown = initCheck((...args) => instance.speedDown(...args));
export const attach = initCheck((...args) => instance.attach(...args));
@ -76,6 +77,7 @@ export const Controls = {
toggleSkip,
toggleSkipToIssue,
toggleAutoplay,
toggleEvents,
toggleSpeed,
speedUp,
speedDown,

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-double-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
<path fill-rule="evenodd" d="M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
</svg>

After

Width:  |  Height:  |  Size: 447 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-double-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L9.293 8 3.646 2.354a.5.5 0 0 1 0-.708z"/>
<path fill-rule="evenodd" d="M7.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L13.293 8 7.646 2.354a.5.5 0 0 1 0-.708z"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B

View file

@ -5,13 +5,13 @@ require('dotenv').config()
const oss = {
name: 'oss',
PRODUCTION: false,
PRODUCTION: true,
SENTRY_ENABLED: false,
SENTRY_URL: "",
CAPTCHA_ENABLED: process.env.CAPTCHA_ENABLED === 'true',
CAPTCHA_SITE_KEY: process.env.CAPTCHA_SITE_KEY,
ORIGIN: () => 'window.location.origin',
API_EDP: 'https://do.openreplay.com/api',
API_EDP: () => 'window.location.origin + "/api"',
ASSETS_HOST: () => 'window.location.origin + "/assets"',
VERSION: '1.0.0',
SOURCEMAP: true,