fix(ui): ui fixes after design review
This commit is contained in:
parent
9d06a95c7a
commit
3031569c07
11 changed files with 91 additions and 85 deletions
|
|
@ -2,46 +2,29 @@ import React, { useState } from 'react'
|
|||
import EventsBlock from '../Session_/EventsBlock';
|
||||
import PageInsightsPanel from '../Session_/PageInsightsPanel/PageInsightsPanel'
|
||||
import { Controls as PlayerControls } from 'Player';
|
||||
import Tabs from './Tabs';
|
||||
import { connectPlayer } from 'Player';
|
||||
import NewBadge from 'Shared/NewBadge';
|
||||
|
||||
const EVENTS = 'Events';
|
||||
const HEATMAPS = 'Click Map';
|
||||
|
||||
const TABS = [ EVENTS, HEATMAPS ].map(tab => ({ text: tab, key: tab }));
|
||||
|
||||
import cn from 'classnames';
|
||||
import stl from './rightblock.css';
|
||||
|
||||
const EventsBlockConnected = connectPlayer(state => ({
|
||||
currentTimeEventIndex: state.eventListNow.length > 0 ? state.eventListNow.length - 1 : 0,
|
||||
playing: state.playing,
|
||||
}))(EventsBlock)
|
||||
|
||||
export default function RightBlock() {
|
||||
const [activeTab, setActiveTab] = useState(EVENTS)
|
||||
export default function RightBlock(props) {
|
||||
const { activeTab } = props;
|
||||
|
||||
const renderActiveTab = (tab) => {
|
||||
switch(tab) {
|
||||
case EVENTS:
|
||||
return <EventsBlockConnected player={PlayerControls}/>
|
||||
case HEATMAPS:
|
||||
case props.tabs.EVENTS:
|
||||
return <EventsBlockConnected setActiveTab={props.setActiveTab} player={PlayerControls}/>
|
||||
case props.tabs.HEATMAPS:
|
||||
return <PageInsightsPanel />
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div style={{ width: '270px', height: 'calc(100vh- 50px)'}} className="flex flex-col bg-white border-l">
|
||||
<div className="relative">
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
active={ activeTab }
|
||||
onClick={ (tab) => setActiveTab(tab) }
|
||||
border={ true }
|
||||
/>
|
||||
<div className="absolute" style={{ left: '160px', top: '13px' }}>{ <NewBadge />}</div>
|
||||
</div>
|
||||
{
|
||||
renderActiveTab(activeTab)
|
||||
}
|
||||
<div className={cn("flex flex-col bg-white border-l", stl.panel)}>
|
||||
{renderActiveTab(activeTab)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Loader } from 'UI';
|
||||
import { toggleFullscreen, closeBottomBlock } from 'Duck/components/player';
|
||||
|
|
@ -9,17 +8,16 @@ import {
|
|||
init as initPlayer,
|
||||
clean as cleanPlayer,
|
||||
Controls,
|
||||
toggleEvents,
|
||||
} from 'Player';
|
||||
import cn from 'classnames'
|
||||
import RightBlock from './RightBlock'
|
||||
import withLocationHandlers from "HOCs/withLocationHandlers";
|
||||
|
||||
|
||||
import PlayerBlockHeader from '../Session_/PlayerBlockHeader';
|
||||
import PlayerBlock from '../Session_/PlayerBlock';
|
||||
import styles from '../Session_/session.module.css';
|
||||
|
||||
|
||||
const InitLoader = connectPlayer(state => ({
|
||||
loading: !state.initialized
|
||||
}))(Loader);
|
||||
|
|
@ -37,15 +35,22 @@ function PlayerContent({ live, fullscreen }) {
|
|||
)
|
||||
}
|
||||
|
||||
function RightMenu({ showEvents, live, fullscreen }) {
|
||||
return showEvents && !live && !fullscreen && <RightBlock />
|
||||
function RightMenu({ showEvents, live, tabs, activeTab, setActiveTab, fullscreen }) {
|
||||
return showEvents && !live && !fullscreen && <RightBlock tabs={tabs} setActiveTab={setActiveTab} activeTab={activeTab} />
|
||||
}
|
||||
const ConnectedMenu = connectPlayer(state => ({
|
||||
showEvents: !state.showEvents}))(RightMenu)
|
||||
showEvents: state.showEvents}), { toggleEvents })(RightMenu)
|
||||
|
||||
function WebPlayer (props) {
|
||||
const { session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt, config, showEvents } = props;
|
||||
|
||||
const TABS = {
|
||||
EVENTS: 'Events',
|
||||
HEATMAPS: 'Click Map',
|
||||
}
|
||||
|
||||
const [activeTab, setActiveTab] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
initPlayer(session, jwt);
|
||||
|
||||
|
|
@ -60,18 +65,17 @@ function WebPlayer (props) {
|
|||
// LAYOUT (TODO: local layout state - useContext or something..)
|
||||
useEffect(() => () => {
|
||||
toggleFullscreen(false);
|
||||
|
||||
closeBottomBlock();
|
||||
}, [])
|
||||
return (
|
||||
<PlayerProvider>
|
||||
<InitLoader className="flex-1">
|
||||
<div className="flex">
|
||||
<div className="w-full">
|
||||
<PlayerBlockHeader fullscreen={fullscreen}/>
|
||||
<PlayerContentConnected fullscreen={fullscreen} live={live} />
|
||||
</div>
|
||||
<ConnectedMenu fullscreen={fullscreen} live={live} />
|
||||
</div>
|
||||
<PlayerBlockHeader activeTab={activeTab} setActiveTab={setActiveTab} tabs={TABS} fullscreen={fullscreen}/>
|
||||
<div className="flex">
|
||||
<div className="w-full"><PlayerContentConnected fullscreen={fullscreen} live={live} /></div>
|
||||
{activeTab !== '' && <ConnectedMenu activeTab={activeTab} setActiveTab={setActiveTab} fullscreen={fullscreen} tabs={TABS} live={live} />}
|
||||
</div>
|
||||
</InitLoader>
|
||||
</PlayerProvider>
|
||||
);
|
||||
|
|
|
|||
5
frontend/app/components/Session/rightblock.css
Normal file
5
frontend/app/components/Session/rightblock.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.panel {
|
||||
width: 270px;
|
||||
height: calc(100vh - 50px);
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { Input, Icon } from 'UI'
|
||||
import { connectPlayer, toggleEvents, scale } from 'Player';
|
||||
|
||||
export default function EventSearch(props) {
|
||||
const { onChange, clearSearch, value, header } = props;
|
||||
const [showSearch, setShowSearch] = useState(true)
|
||||
function EventSearch(props) {
|
||||
const { onChange, clearSearch, value, header, toggleEvents, setActiveTab } = props;
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -11,23 +11,18 @@ export default function EventSearch(props) {
|
|||
}
|
||||
}, [])
|
||||
|
||||
const toggleSearch = () => {
|
||||
setShowSearch(!showSearch)
|
||||
clearSearch();
|
||||
}
|
||||
return (
|
||||
<div className="flex items-center w-full relative">
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className='flex flex-center justify-between'>
|
||||
<span>{header}</span>
|
||||
<div
|
||||
onClick={() => toggleSearch()}
|
||||
onClick={() => { toggleEvents(); setActiveTab('')}}
|
||||
className=" flex items-center justify-center bg-white cursor-pointer"
|
||||
>
|
||||
<Icon name={ showSearch ? 'close' : 'search'} size="18" />
|
||||
<Icon name="close" size="18" />
|
||||
</div>
|
||||
</div>
|
||||
{showSearch && (
|
||||
<div className="flex items-center mt-2">
|
||||
<Input
|
||||
autoFocus
|
||||
|
|
@ -41,8 +36,9 @@ export default function EventSearch(props) {
|
|||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default connectPlayer(() => null, { toggleEvents })(EventSearch)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { TYPES } from 'Types/session/event';
|
|||
import { setSelected } from 'Duck/events';
|
||||
import { setEventFilter } from 'Duck/sessions';
|
||||
import { show as showTargetDefiner } from 'Duck/components/targetDefiner';
|
||||
import UserCard from './UserCard';
|
||||
import EventGroupWrapper from './EventGroupWrapper';
|
||||
import styles from './eventsBlock.module.css';
|
||||
import EventSearch from './EventSearch/EventSearch';
|
||||
|
|
@ -185,7 +184,8 @@ export default class EventsBlock extends React.PureComponent {
|
|||
revId,
|
||||
userAnonymousId
|
||||
},
|
||||
filteredEvents
|
||||
filteredEvents,
|
||||
setActiveTab,
|
||||
} = this.props;
|
||||
|
||||
const _events = filteredEvents || events;
|
||||
|
|
@ -197,6 +197,7 @@ export default class EventsBlock extends React.PureComponent {
|
|||
<EventSearch
|
||||
onChange={this.write}
|
||||
clearSearch={this.clearSearch}
|
||||
setActiveTab={setActiveTab}
|
||||
value={query}
|
||||
header={
|
||||
<div className="text-xl">User Events <span className="color-gray-medium">{ events.size }</span></div>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ export default class Player extends React.PureComponent {
|
|||
data-bottom-block={ bottomBlockIsActive }
|
||||
>
|
||||
{fullscreen && <EscapeButton onClose={ fullscreenOff } />}
|
||||
{!live && !fullscreen && <EventsToggleButton /> }
|
||||
<div className="relative flex-1 overflow-hidden">
|
||||
<Overlay nextId={nextId} togglePlay={PlayerControls.togglePlay} closedLive={closedLive} />
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@ import { sessions as sessionsRoute, assist as assistRoute, liveSession as liveSe
|
|||
import { Button, Icon, BackLink, Link } from 'UI';
|
||||
import { toggleFavorite, setSessionPath } from 'Duck/sessions';
|
||||
import cn from 'classnames';
|
||||
import { connectPlayer } from 'Player';
|
||||
import SharePopup from '../shared/SharePopup/SharePopup';
|
||||
import { Icon, BackLink, Link } from 'UI';
|
||||
import { connectPlayer, showEvents, toggleEvents } from 'Player';
|
||||
import { fetchList as fetchListIntegration } from 'Duck/integrations/actions';
|
||||
import SessionMetaList from 'Shared/SessionItem/SessionMetaList';
|
||||
import Bookmark from 'Shared/Bookmark'
|
||||
import UserCard from './EventsBlock/UserCard';
|
||||
import Tabs from 'Components/Session/Tabs';
|
||||
import NewBadge from 'Shared/NewBadge';
|
||||
|
||||
import stl from './playerBlockHeader.module.css';
|
||||
import Issues from './Issues/Issues';
|
||||
import Autoplay from './Autoplay';
|
||||
import AssistActions from '../Assist/components/AssistActions';
|
||||
import AssistTabs from '../Assist/components/AssistTabs';
|
||||
|
||||
|
|
@ -25,10 +27,12 @@ const ASSIST_ROUTE = assistRoute();
|
|||
height: state.height,
|
||||
live: state.live,
|
||||
loading: state.cssLoading || state.messagesLoading,
|
||||
}))
|
||||
showEvents: state.showEvents,
|
||||
}), { toggleEvents })
|
||||
@connect((state, props) => {
|
||||
const isAssist = window.location.pathname.includes('/assist/');
|
||||
const session = state.getIn([ 'sessions', 'current' ]);
|
||||
|
||||
return {
|
||||
isAssist,
|
||||
session,
|
||||
|
|
@ -80,6 +84,10 @@ export default class PlayerBlockHeader extends React.PureComponent {
|
|||
closedLive = false,
|
||||
siteId,
|
||||
isAssist,
|
||||
setActiveTab,
|
||||
activeTab,
|
||||
showEvents,
|
||||
toggleEvents,
|
||||
} = this.props;
|
||||
// const _live = isAssist;
|
||||
|
||||
|
|
@ -96,6 +104,8 @@ export default class PlayerBlockHeader extends React.PureComponent {
|
|||
return { label: key, value };
|
||||
});
|
||||
|
||||
const TABS = [ this.props.tabs.EVENTS, this.props.tabs.HEATMAPS ].map(tab => ({ text: tab, key: tab }));
|
||||
console.log(showEvents, activeTab)
|
||||
return (
|
||||
<div className={ cn(stl.header, "flex justify-between", { "hidden" : fullscreen}) }>
|
||||
<div className="flex w-full items-center">
|
||||
|
|
@ -127,6 +137,15 @@ export default class PlayerBlockHeader extends React.PureComponent {
|
|||
{ !isAssist && jiraConfig && jiraConfig.token && <Issues sessionId={ sessionId } /> }
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative" style={{ minWidth: '270px' }}>
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
active={ activeTab }
|
||||
onClick={ (tab) => { setActiveTab(tab); !showEvents && toggleEvents(true) } }
|
||||
border={ true }
|
||||
/>
|
||||
<div className="absolute" style={{ left: '160px', top: '13px' }}>{ <NewBadge />}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ function SubHeader(props) {
|
|||
|
||||
const location = props.currentLocation && props.currentLocation.length > 60 ? `${props.currentLocation.slice(0, 60)}...` : props.currentLocation
|
||||
return (
|
||||
<div className="w-full px-4 py-2 flex items-center">
|
||||
<div className="w-full px-4 py-2 flex items-center border-b">
|
||||
{location && (
|
||||
<div
|
||||
className="flex items-center cursor-pointer color-gray-medium text-xs p-2 hover:bg-gray-light-shade rounded-md"
|
||||
className="flex items-center cursor-pointer color-gray-medium text-sm p-1 hover:bg-gray-light-shade rounded-md"
|
||||
onClick={() => {
|
||||
copy(props.currentLocation);
|
||||
setCopied(true)
|
||||
|
|
@ -38,14 +38,14 @@ function SubHeader(props) {
|
|||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
<div className="ml-auto text-xs flex items-center color-gray-medium" style={{ width: 'max-content' }}>
|
||||
<div className="ml-auto text-sm flex items-center color-gray-medium" style={{ width: 'max-content' }}>
|
||||
<div className="cursor-pointer">
|
||||
<SharePopup
|
||||
entity="sessions"
|
||||
id={ props.sessionId }
|
||||
showCopyLink={true}
|
||||
trigger={
|
||||
<div className="flex items-center hover:bg-gray-light-shade rounded-md p-2">
|
||||
<div className="flex items-center hover:bg-gray-light-shade rounded-md p-1">
|
||||
<Icon
|
||||
className="mr-2"
|
||||
disabled={ props.disabled }
|
||||
|
|
@ -58,7 +58,7 @@ function SubHeader(props) {
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-2 hover:bg-gray-light-shade rounded-md p-2">
|
||||
<div className="mx-2 hover:bg-gray-light-shade rounded-md p-1">
|
||||
<Bookmark noMargin />
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
.header {
|
||||
height: 50px;
|
||||
border-bottom: solid thin $gray-light;
|
||||
padding: 0px 15px;
|
||||
padding-left: 15px;
|
||||
padding-right: 0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,27 +25,25 @@ import Exceptions from './Exceptions/Exceptions';
|
|||
import LongTasks from './LongTasks';
|
||||
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
key: CONSOLE,
|
||||
Component: Console,
|
||||
},
|
||||
{
|
||||
key: NETWORK,
|
||||
Component: Network,
|
||||
},
|
||||
{
|
||||
key: STORAGE,
|
||||
Component:
|
||||
}
|
||||
]
|
||||
// const tabs = [
|
||||
// {
|
||||
// key: CONSOLE,
|
||||
// Component: Console,
|
||||
// },
|
||||
// {
|
||||
// key: NETWORK,
|
||||
// Component: Network,
|
||||
// },
|
||||
// {
|
||||
// key: STORAGE,
|
||||
// Component:
|
||||
// }
|
||||
// ]
|
||||
|
||||
const tabsByKey = {};
|
||||
tabs.map()
|
||||
// tabs.map()
|
||||
|
||||
|
||||
export function switchTab(tabKey) {
|
||||
tabKey
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -213,8 +213,8 @@ export default class Player extends MessageDistributor {
|
|||
update({ autoplay });
|
||||
}
|
||||
|
||||
toggleEvents() {
|
||||
const showEvents = !getState().showEvents;
|
||||
toggleEvents(shouldShow = undefined) {
|
||||
const showEvents = shouldShow || !getState().showEvents;
|
||||
localStorage.setItem(SHOW_EVENTS_STORAGE_KEY, `${showEvents}`);
|
||||
update({ showEvents });
|
||||
}
|
||||
|
|
@ -243,4 +243,4 @@ export default class Player extends MessageDistributor {
|
|||
this.pause();
|
||||
super.clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue