change(ui) - live sessions maintain query params

This commit is contained in:
Shekar Siri 2022-07-22 18:52:30 +02:00
parent e4b77669da
commit ef679a275f
3 changed files with 178 additions and 181 deletions

View file

@ -1,44 +1,42 @@
import React, { useState, useEffect } from 'react'
import {
Link,
Icon,
} from 'UI';
import React, { useState, useEffect } from 'react';
import { Link, Icon } from 'UI';
import { session as sessionRoute, liveSession as liveSessionRoute } from 'App/routes';
const PLAY_ICON_NAMES = {
notPlayed: 'play-fill',
played: 'play-circle-light',
hovered: 'play-hover'
}
hovered: 'play-hover',
};
const getDefaultIconName = (isViewed) => !isViewed ? PLAY_ICON_NAMES.notPlayed : PLAY_ICON_NAMES.played
const getDefaultIconName = (isViewed: any) => (!isViewed ? PLAY_ICON_NAMES.notPlayed : PLAY_ICON_NAMES.played);
interface Props {
isAssist: boolean;
viewed: boolean;
sessionId: string;
onClick?: () => void;
queryParams: any;
}
export default function PlayLink(props: Props) {
const { isAssist, viewed, sessionId, onClick = null } = props
const defaultIconName = getDefaultIconName(viewed)
const { isAssist, viewed, sessionId, onClick = null, queryParams } = props;
const defaultIconName = getDefaultIconName(viewed);
const [isHovered, toggleHover] = useState(false)
const [iconName, setIconName] = useState(defaultIconName)
const [isHovered, toggleHover] = useState(false);
const [iconName, setIconName] = useState(defaultIconName);
useEffect(() => {
if (isHovered) setIconName(PLAY_ICON_NAMES.hovered)
else setIconName(getDefaultIconName(viewed))
}, [isHovered, viewed])
if (isHovered) setIconName(PLAY_ICON_NAMES.hovered);
else setIconName(getDefaultIconName(viewed));
}, [isHovered, viewed]);
return (
<Link
onClick={onClick ? onClick : () => {}}
to={ isAssist ? liveSessionRoute(sessionId) : sessionRoute(sessionId) }
to={isAssist ? liveSessionRoute(sessionId, queryParams) : sessionRoute(sessionId)}
onMouseEnter={() => toggleHover(true)}
onMouseLeave={() => toggleHover(false)}
>
<Icon name={iconName} size={38} color={isAssist ? "tealx" : "teal"} />
<Icon name={iconName} size={38} color={isAssist ? 'tealx' : 'teal'} />
</Link>
)
}
);
}

View file

@ -1,192 +1,191 @@
import React from 'react'
import React, { useEffect } from 'react';
import cn from 'classnames';
import {
CountryFlag,
Avatar,
TextEllipsis,
Label,
Icon,
} from 'UI';
import { CountryFlag, Avatar, TextEllipsis, Label, Icon } from 'UI';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { durationFormatted, formatTimeOrDate } from 'App/date';
import stl from './sessionItem.module.css';
import Counter from './Counter'
import Counter from './Counter';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import SessionMetaList from './SessionMetaList';
import PlayLink from './PlayLink';
import ErrorBars from './ErrorBars';
import { assist as assistRoute, liveSession, sessions as sessionsRoute, isRoute } from "App/routes";
import { assist as assistRoute, liveSession, sessions as sessionsRoute, isRoute } from 'App/routes';
import { capitalize } from 'App/utils';
const ASSIST_ROUTE = assistRoute();
const ASSIST_LIVE_SESSION = liveSession()
const ASSIST_LIVE_SESSION = liveSession();
const SESSIONS_ROUTE = sessionsRoute();
interface Props {
session: {
sessionId: string;
userBrowser: string;
userOs: string;
userId: string;
userAnonymousId: string;
userDisplayName: string;
userCountry: string;
startedAt: number;
duration: string;
eventsCount: number;
errorsCount: number;
pagesCount: number;
viewed: boolean;
favorite: boolean;
userDeviceType: string;
userUuid: string;
userNumericHash: number;
live: boolean;
metadata: Record<string, any>;
userSessionsCount: number;
issueTypes: [];
active: boolean;
},
onUserClick?: (userId: string, userAnonymousId: string) => void;
hasUserFilter?: boolean;
disableUser?: boolean;
metaList?: Array<any>;
// showActive?: boolean;
lastPlayedSessionId?: string;
live?: boolean;
onClick?: any
session: {
sessionId: string;
userBrowser: string;
userOs: string;
userId: string;
userAnonymousId: string;
userDisplayName: string;
userCountry: string;
startedAt: number;
duration: string;
eventsCount: number;
errorsCount: number;
pagesCount: number;
viewed: boolean;
favorite: boolean;
userDeviceType: string;
userUuid: string;
userNumericHash: number;
live: boolean;
metadata: Record<string, any>;
userSessionsCount: number;
issueTypes: [];
active: boolean;
};
onUserClick?: (userId: string, userAnonymousId: string) => void;
hasUserFilter?: boolean;
disableUser?: boolean;
metaList?: Array<any>;
// showActive?: boolean;
lastPlayedSessionId?: string;
live?: boolean;
onClick?: any;
}
function SessionItem(props: RouteComponentProps & Props) {
const { settingsStore } = useStore();
const { timezone } = settingsStore.sessionSettings;
const { settingsStore } = useStore();
const { timezone } = settingsStore.sessionSettings;
const [isIframe, setIsIframe] = React.useState(false);
const {
session,
onUserClick = () => null,
hasUserFilter = false,
disableUser = false,
metaList = [],
lastPlayedSessionId,
onClick = null,
} = props;
const {
session,
onUserClick = () => null,
hasUserFilter = false,
disableUser = false,
metaList = [],
lastPlayedSessionId,
onClick = null,
} = props;
const {
sessionId,
userBrowser,
userOs,
userId,
userAnonymousId,
userDisplayName,
userCountry,
startedAt,
duration,
eventsCount,
viewed,
userDeviceType,
userNumericHash,
live,
metadata,
issueTypes,
active,
} = session;
const {
sessionId,
userBrowser,
userOs,
userId,
userAnonymousId,
userDisplayName,
userCountry,
startedAt,
duration,
eventsCount,
viewed,
userDeviceType,
userNumericHash,
live,
metadata,
issueTypes,
active,
} = session;
const location = props.location;
const location = props.location;
const queryParams = Object.fromEntries(new URLSearchParams(location.search));
const formattedDuration = durationFormatted(duration);
const hasUserId = userId || userAnonymousId;
const isSessions = isRoute(SESSIONS_ROUTE, location.pathname);
const isAssist = isRoute(ASSIST_ROUTE, location.pathname) || isRoute(ASSIST_LIVE_SESSION, location.pathname);
const isLastPlayed = lastPlayedSessionId === sessionId;
const formattedDuration = durationFormatted(duration);
const hasUserId = userId || userAnonymousId;
const isSessions = isRoute(SESSIONS_ROUTE, location.pathname);
const isAssist = isRoute(ASSIST_ROUTE, location.pathname) || isRoute(ASSIST_LIVE_SESSION, location.pathname);
const isLastPlayed = lastPlayedSessionId === sessionId;
const _metaList = Object.keys(metadata).filter(i => metaList.includes(i)).map(key => {
const value = metadata[key];
return { label: key, value };
});
const _metaList = Object.keys(metadata)
.filter((i) => metaList.includes(i))
.map((key) => {
const value = metadata[key];
return { label: key, value };
});
return (
<div className={ cn(stl.sessionItem, "flex flex-col p-2") } id="session-item" onClick={(e) => e.stopPropagation()}>
<div className="flex items-start">
<div className={ cn('flex items-center w-full')}>
<div className="flex items-center pr-2 shrink-0" style={{ width: "40%"}}>
<div><Avatar isActive={active} seed={ userNumericHash } isAssist={isAssist} /></div>
<div className="flex flex-col overflow-hidden color-gray-medium ml-3 justify-between items-center shrink-0">
<div
className={cn('text-lg', {'color-teal cursor-pointer': !disableUser && hasUserId, [stl.userName]: !disableUser && hasUserId, 'color-gray-medium' : disableUser || !hasUserId})}
onClick={() => (!disableUser && !hasUserFilter) && onUserClick(userId, userAnonymousId)}
>
<TextEllipsis text={userDisplayName} maxWidth="200px" popupProps={{ inverted: true, size: 'tiny' }} />
return (
<div className={cn(stl.sessionItem, 'flex flex-col p-2')} id="session-item" onClick={(e) => e.stopPropagation()}>
<div className="flex items-start">
<div className={cn('flex items-center w-full')}>
<div className="flex items-center pr-2 shrink-0" style={{ width: '40%' }}>
<div>
<Avatar isActive={active} seed={userNumericHash} isAssist={isAssist} />
</div>
<div className="flex flex-col overflow-hidden color-gray-medium ml-3 justify-between items-center shrink-0">
<div
className={cn('text-lg', {
'color-teal cursor-pointer': !disableUser && hasUserId,
[stl.userName]: !disableUser && hasUserId,
'color-gray-medium': disableUser || !hasUserId,
})}
onClick={() => !disableUser && !hasUserFilter && onUserClick(userId, userAnonymousId)}
>
<TextEllipsis text={userDisplayName} maxWidth="200px" popupProps={{ inverted: true, size: 'tiny' }} />
</div>
</div>
</div>
<div style={{ width: '20%' }} className="px-2 flex flex-col justify-between">
<div>
<TextEllipsis text={formatTimeOrDate(startedAt, timezone)} popupProps={{ inverted: true, size: 'tiny' }} />
</div>
<div className="flex items-center color-gray-medium py-1">
{!isAssist && (
<>
<div className="color-gray-medium">
<span className="mr-1">{eventsCount}</span>
<span>{eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event'}</span>
</div>
<Icon name="circle-fill" size={3} className="mx-4" />
</>
)}
<div>{live ? <Counter startTime={startedAt} /> : formattedDuration}</div>
</div>
</div>
<div style={{ width: '30%' }} className="px-2 flex flex-col justify-between">
<div style={{ height: '21px' }}>
<CountryFlag country={userCountry} style={{ paddingTop: '4px' }} label />
</div>
<div className="color-gray-medium flex items-center py-1">
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userBrowser)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userOs)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userDeviceType)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
</div>
</div>
{isSessions && (
<div style={{ width: '10%' }} className="self-center px-2 flex items-center">
<ErrorBars count={issueTypes.length} />
</div>
)}
</div>
</div>
</div>
<div style={{ width: "20%" }} className="px-2 flex flex-col justify-between">
<div>
<TextEllipsis text={formatTimeOrDate(startedAt, timezone)} popupProps={{ inverted: true, size: 'tiny' }} />
</div>
<div className="flex items-center color-gray-medium py-1">
{!isAssist && (
<>
<div className="color-gray-medium">
<span className="mr-1">{ eventsCount }</span>
<span>{ eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event' }</span>
</div>
<Icon name="circle-fill" size={3} className="mx-4" />
</>
)}
<div>{ live ? <Counter startTime={startedAt} /> : formattedDuration }</div>
</div>
</div>
<div style={{ width: "30%" }} className="px-2 flex flex-col justify-between">
<div style={{ height: '21px'}}>
<CountryFlag country={ userCountry } style={{ paddingTop: '4px' }} label />
</div>
<div className="color-gray-medium flex items-center py-1">
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userBrowser) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userOs) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userDeviceType) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
</div>
</div>
{ isSessions && (
<div style={{ width: "10%"}} className="self-center px-2 flex items-center">
<ErrorBars count={issueTypes.length} />
</div>
)}
</div>
<div className="flex items-center">
<div className={ stl.playLink } id="play-button" data-viewed={ viewed }>
{ isSessions && (
<div className="mr-4 flex-shrink-0 w-24">
{ isLastPlayed && (
<Label className="bg-gray-lightest p-1 px-2 rounded-lg">
<span className="color-gray-medium text-xs" style={{ whiteSpace: 'nowrap'}}>LAST PLAYED</span>
</Label>
)}
<div className="flex items-center">
<div className={stl.playLink} id="play-button" data-viewed={viewed}>
{isSessions && (
<div className="mr-4 flex-shrink-0 w-24">
{isLastPlayed && (
<Label className="bg-gray-lightest p-1 px-2 rounded-lg">
<span className="color-gray-medium text-xs" style={{ whiteSpace: 'nowrap' }}>
LAST PLAYED
</span>
</Label>
)}
</div>
)}
<PlayLink isAssist={isAssist} sessionId={sessionId} viewed={viewed} onClick={onClick} queryParams={queryParams} />
</div>
</div>
)}
<PlayLink
isAssist={isAssist}
sessionId={sessionId}
viewed={viewed}
onClick={onClick}
/>
</div>
</div>
{_metaList.length > 0 && <SessionMetaList className="mt-4" metaList={_metaList} />}
</div>
{ _metaList.length > 0 && (
<SessionMetaList className="mt-4" metaList={_metaList} />
)}
</div>
)
);
}
export default withRouter<Props>(observer<Props>(SessionItem))
export default withRouter<Props>(observer<Props>(SessionItem));

View file

@ -86,7 +86,7 @@ export const sessions = params => queried('/sessions', params);
export const assist = params => queried('/assist', params);
export const session = (sessionId = ':sessionId', hash) => hashed(`/session/${ sessionId }`, hash);
export const liveSession = (sessionId = ':sessionId', hash) => hashed(`/assist/${ sessionId }`, hash);
export const liveSession = (sessionId = ':sessionId', params, hash) => hashed(queried(`/assist/${ sessionId }`, params), hash);
// export const liveSession = (sessionId = ':sessionId', hash) => hashed(`/live/session/${ sessionId }`, hash);
export const errors = params => queried('/errors', params);