@@ -117,15 +123,33 @@ export default class PlayerBlockHeader extends React.PureComponent {
+
+
+ )}
+ content={(
+
+ } label={countries[userCountry]} value={ formatTimeOrDate(startedAt) } />
+
+
+
+
+ )}
+ on="click"
+ position="top center"
+ hideOnScroll
+ />
+
+
{ live && hasSessionsPath && (
this.props.setSessionPath('')}>
This Session is Now Continuing Live
)}
- { _live &&
}
{ _live &&
}
{ !_live && (
<>
@@ -164,3 +188,4 @@ export default class PlayerBlockHeader extends React.PureComponent {
);
}
}
+
diff --git a/frontend/app/components/Session_/SessionInfoItem/SessionInfoItem.tsx b/frontend/app/components/Session_/SessionInfoItem/SessionInfoItem.tsx
new file mode 100644
index 000000000..f89bfb9cd
--- /dev/null
+++ b/frontend/app/components/Session_/SessionInfoItem/SessionInfoItem.tsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { Icon } from 'UI'
+import cn from 'classnames'
+
+interface Props {
+ label: string,
+ icon?: string,
+ comp?: React.ReactNode,
+ value: string,
+ isLast?: boolean,
+}
+export default function SessionInfoItem(props: Props) {
+ const { label, icon, value, comp, isLast = false } = props
+ return (
+
+
+ { icon && }
+ { comp && comp }
+
+
{label}
+
{value}
+
+ )
+}
diff --git a/frontend/app/components/Session_/SessionInfoItem/index.ts b/frontend/app/components/Session_/SessionInfoItem/index.ts
new file mode 100644
index 000000000..372f8dea8
--- /dev/null
+++ b/frontend/app/components/Session_/SessionInfoItem/index.ts
@@ -0,0 +1 @@
+export { default } from './SessionInfoItem';
\ No newline at end of file
diff --git a/frontend/app/components/Session_/playerBlockHeader.css b/frontend/app/components/Session_/playerBlockHeader.css
index d9934ef1e..764933a16 100644
--- a/frontend/app/components/Session_/playerBlockHeader.css
+++ b/frontend/app/components/Session_/playerBlockHeader.css
@@ -1,13 +1,13 @@
.header {
height: 50px;
border-bottom: solid thin $gray-light;
- padding: 10px 15px;
+ padding: 0px 15px;
background-color: white;
}
.divider {
width: 1px;
- height: 100%;
+ height: 49px;
margin: 0 15px;
background-color: $gray-light;
}
diff --git a/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.css b/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.css
new file mode 100644
index 000000000..e88de9b3b
--- /dev/null
+++ b/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.css
@@ -0,0 +1,3 @@
+.bar {
+ height: 2px;
+}
\ No newline at end of file
diff --git a/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.tsx b/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.tsx
index 64c7f91b4..31c233414 100644
--- a/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.tsx
+++ b/frontend/app/components/shared/SessionItem/ErrorBars/ErrorBars.tsx
@@ -1,5 +1,6 @@
import React from 'react'
import cn from 'classnames'
+import stl from './ErrorBars.css'
const GOOD = 'Good'
const LESS_CRITICAL = 'Less Critical'
@@ -16,21 +17,23 @@ interface Props {
}
export default function ErrorBars(props: Props) {
const { count = 2 } = props
- const state = React.useCallback(() => getErrorState(count), [count])()
+ const state = React.useMemo(() => getErrorState(count), [count])
+ const showSecondBar = (state === GOOD || state === LESS_CRITICAL || state === CRITICAL)
+ const showThirdBar = (state === GOOD || state === CRITICAL);
const bgColor = { 'bg-red' : state === CRITICAL, 'bg-green' : state === GOOD, 'bg-red2' : state === LESS_CRITICAL }
return (
-
+
-
- { (state === GOOD || state === LESS_CRITICAL || state === CRITICAL) &&
}
- { (state === GOOD || state === CRITICAL) &&
}
+
+ { showSecondBar &&
}
+ { showThirdBar &&
}
-
{state}
+
{state}
)
}
diff --git a/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx b/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx
new file mode 100644
index 000000000..1d2df4b04
--- /dev/null
+++ b/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx
@@ -0,0 +1,22 @@
+import React from 'react'
+import cn from 'classnames'
+import { TextEllipsis } from 'UI'
+
+interface Props {
+ className?: string,
+ label: string,
+ value?: string,
+}
+export default function MetaItem(props: Props) {
+ const { className = '', label, value } = props
+ return (
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/frontend/app/components/shared/SessionItem/MetaItem/index.ts b/frontend/app/components/shared/SessionItem/MetaItem/index.ts
new file mode 100644
index 000000000..f25b30c65
--- /dev/null
+++ b/frontend/app/components/shared/SessionItem/MetaItem/index.ts
@@ -0,0 +1 @@
+export { default } from './MetaItem';
\ No newline at end of file
diff --git a/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx b/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx
new file mode 100644
index 000000000..21a5f38f1
--- /dev/null
+++ b/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx
@@ -0,0 +1,32 @@
+import React from 'react'
+import { Popup } from 'UI'
+import MetaItem from '../MetaItem'
+
+interface Props {
+ list: any[],
+ maxLength: number,
+}
+export default function MetaMoreButton(props: Props) {
+ const { list, maxLength } = props
+ return (
+
+
+ +{list.length - maxLength} More
+
+
+ ) }
+ content={
+
+ {list.slice(maxLength).map(({ label, value }, index) => (
+
+ ))}
+
+ }
+ on="click"
+ position="top right"
+ hideOnScroll
+ />
+ )
+}
diff --git a/frontend/app/components/shared/SessionItem/MetaMoreButton/index.ts b/frontend/app/components/shared/SessionItem/MetaMoreButton/index.ts
new file mode 100644
index 000000000..8a1f4733e
--- /dev/null
+++ b/frontend/app/components/shared/SessionItem/MetaMoreButton/index.ts
@@ -0,0 +1 @@
+export { default } from './MetaMoreButton';
\ No newline at end of file
diff --git a/frontend/app/components/shared/SessionItem/SessionItem.js b/frontend/app/components/shared/SessionItem/SessionItem.js
index 7d39e8e4e..4956342f0 100644
--- a/frontend/app/components/shared/SessionItem/SessionItem.js
+++ b/frontend/app/components/shared/SessionItem/SessionItem.js
@@ -20,13 +20,15 @@ import Counter from './Counter'
import { withRouter } from 'react-router-dom';
import SessionMetaList from './SessionMetaList';
import ErrorBars from './ErrorBars';
+import { assist as assistRoute, isRoute } from "App/routes";
+
+const ASSIST_ROUTE = assistRoute();
const Label = ({ label = '', color = 'color-gray-medium'}) => (
{label}
)
@connect(state => ({
timezone: state.getIn(['sessions', 'timezone']),
- isAssist: state.getIn(['sessions', 'activeTab']).type === 'live',
siteId: state.getIn([ 'user', 'siteId' ]),
}), { toggleFavorite, setSessionPath })
@withRouter
@@ -52,7 +54,8 @@ export default class SessionItem extends React.PureComponent {
userDeviceType,
userUuid,
userNumericHash,
- live
+ live,
+ metadata,
},
timezone,
onUserClick = () => null,
@@ -61,71 +64,89 @@ export default class SessionItem extends React.PureComponent {
} = this.props;
const formattedDuration = durationFormatted(duration);
const hasUserId = userId || userAnonymousId;
+ const isAssist = isRoute(ASSIST_ROUTE, this.props.location.pathname);
+ console.log('metadata', metadata);
+
+ const _metaList = Object.keys(metadata).map(key => {
+ const value = metadata[key];
+ return { label: key, value };
+ });
+
+ console.log('SessionItem', _metaList);
return (
-
-
-
+
+
+ {/*
*/}
+
(!disableUser && !hasUserFilter && hasUserId) && onUserClick(userId, userAnonymousId)}
>
{userDisplayName}
-
30 Sessions
-
-
-
-
{formatTimeOrDate(startedAt, timezone) }
-
- {!live && (
-
- { eventsCount }
- { eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event' }
-
- )}
-
-
-
{ live ? : formattedDuration }
-
-
-
-
-
-
-
{userBrowser} -
-
{userOs} -
-
{userDeviceType}
+
(!disableUser && !hasUserFilter && hasUserId) && onUserClick(userId, userAnonymousId)}
+ >
+ 30 Sessions
-
-
+
+
{formatTimeOrDate(startedAt, timezone) }
+
+ {!isAssist && (
+ <>
+
+ { eventsCount }
+ { eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event' }
+
+
·
+ >
+ )}
+
{ live ? : formattedDuration }
+
+
+ {/*
*/}
+
+
+
+
+
+
·
+
+
+
+
·
+
+
+
+
+ {/*
*/}
+
+ { !isAssist && (
+
+
+
+ )}
- {/* { live &&
} */}
-
-
-
-
-
+
-
+ { isAssist && (
+
+ )}
);
}
diff --git a/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx b/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx
index 3abc72041..96b082e96 100644
--- a/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx
+++ b/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx
@@ -1,6 +1,8 @@
import React from 'react'
import { Popup } from 'UI'
import cn from 'classnames'
+import MetaItem from '../MetaItem';
+import MetaMoreButton from '../MetaMoreButton';
interface Props {
className?: string,
@@ -12,36 +14,11 @@ export default function SessionMetaList(props: Props) {
return (
{metaList.slice(0, MAX_LENGTH).map(({ label, value }, index) => (
-
- {label}
- {value}
-
+
))}
{metaList.length > MAX_LENGTH && (
-
-
- +{metaList.length - MAX_LENGTH} More
-
-
- ) }
- content={
-
- {metaList.slice(MAX_LENGTH).map(({ label, value }, index) => (
-
- {label}
- {value}
-
- ))}
-
- }
- on="click"
- position="top right"
- // className={ styles.popup }
- hideOnScroll
- />
+
)}
)
diff --git a/frontend/app/components/ui/Avatar/Avatar.js b/frontend/app/components/ui/Avatar/Avatar.js
index b369c5e30..fd1ca884b 100644
--- a/frontend/app/components/ui/Avatar/Avatar.js
+++ b/frontend/app/components/ui/Avatar/Avatar.js
@@ -11,14 +11,15 @@ const ICON_LIST = ['icn_chameleon', 'icn_fox', 'icn_gorilla', 'icn_hippo', 'icn_
'icn_wild1', 'icn_wild_bore']
-const Avatar = ({ className, width = "38px", height = "38px", iconSize = 26, seed }) => {
+const Avatar = ({ isAssist = false, className, width = "38px", height = "38px", iconSize = 26, seed }) => {
var iconName = avatarIconName(seed);
return (
);
};
diff --git a/frontend/app/components/ui/CountryFlag/CountryFlag.js b/frontend/app/components/ui/CountryFlag/CountryFlag.js
index 0ba14c967..04cfaf38d 100644
--- a/frontend/app/components/ui/CountryFlag/CountryFlag.js
+++ b/frontend/app/components/ui/CountryFlag/CountryFlag.js
@@ -3,22 +3,26 @@ import { countries } from 'App/constants';
import { Popup } from 'UI';
import stl from './countryFlag.css';
-const CountryFlag = ({ country, className }) => {
+const CountryFlag = React.memo(({ country, className, style = {}, label = false }) => {
const knownCountry = !!country && country !== 'UN';
- const countryFlag = knownCountry ? country.toLowerCase() : '';
- const countryName = knownCountry ? countries[ country ] : 'Unknown Country';
+ const countryFlag = knownCountry ? country.toLowerCase() : '';
+ const countryName = knownCountry ? countries[ country ] : 'Unknown Country';
+
return (
-
- :
{ "N/A" }
- }
- content={ countryName }
- inverted
- size="tiny"
- />
+
+
+ :
{ "N/A" }
+ }
+ content={ countryName }
+ inverted
+ size="tiny"
+ />
+ { knownCountry && label &&
{ countryName }
}
+
);
-}
+})
CountryFlag.displayName = "CountryFlag";
diff --git a/frontend/app/components/ui/CountryFlag/countryFlag.css b/frontend/app/components/ui/CountryFlag/countryFlag.css
index 29a5d880b..4cbc1f39b 100644
--- a/frontend/app/components/ui/CountryFlag/countryFlag.css
+++ b/frontend/app/components/ui/CountryFlag/countryFlag.css
@@ -1,4 +1,8 @@
.default {
width: 22px !important;
height: 14px !important;
+}
+
+.label {
+ line-height: 0 !important;
}
\ No newline at end of file
diff --git a/frontend/app/components/ui/IconButton/IconButton.js b/frontend/app/components/ui/IconButton/IconButton.js
index eb708f21a..6aa9f3d5f 100644
--- a/frontend/app/components/ui/IconButton/IconButton.js
+++ b/frontend/app/components/ui/IconButton/IconButton.js
@@ -9,8 +9,10 @@ const IconButton = React.forwardRef(({
onClick,
plain = false,
shadow = false,
+ red = false,
primary = false,
primaryText = false,
+ redText = false,
outline = false,
loading = false,
roundedOutline = false,
@@ -40,7 +42,9 @@ const IconButton = React.forwardRef(({
[ stl.active ]: active,
[ stl.shadow ]: shadow,
[ stl.primary ]: primary,
+ [ stl.red ]: red,
[ stl.primaryText ]: primaryText,
+ [ stl.redText ]: redText,
[ stl.outline ]: outline,
[ stl.circle ]: circle,
[ stl.roundedOutline ]: roundedOutline,
diff --git a/frontend/app/components/ui/IconButton/iconButton.css b/frontend/app/components/ui/IconButton/iconButton.css
index 1685ca4d6..11b3dd51f 100644
--- a/frontend/app/components/ui/IconButton/iconButton.css
+++ b/frontend/app/components/ui/IconButton/iconButton.css
@@ -73,11 +73,41 @@
fill: white;
}
+ & svg {
+ fill: white;
+ }
+
+ & .label {
+ color: white !important;
+ }
+
&:hover {
background-color: $teal-dark;
}
}
+ &.red {
+ background-color: $red;
+ box-shadow: 0 0 0 1px $red inset !important;
+
+ & .icon {
+ fill: white;
+ }
+
+ & svg {
+ fill: white;
+ }
+
+ & .label {
+ color: white !important;
+ }
+
+ &:hover {
+ background-color: $red;
+ filter: brightness(90%);
+ }
+ }
+
&.outline {
box-shadow: 0 0 0 1px $teal inset !important;
& .label {
@@ -116,4 +146,14 @@
.primaryText .label {
color: $teal !important;
+}
+
+.redText {
+ & .label {
+ color: $red !important;
+ }
+
+ & svg {
+ fill: $red;
+ }
}
\ No newline at end of file
diff --git a/frontend/app/components/ui/TextEllipsis/textEllipsis.css b/frontend/app/components/ui/TextEllipsis/textEllipsis.css
index 9baca35cc..9919f9160 100644
--- a/frontend/app/components/ui/TextEllipsis/textEllipsis.css
+++ b/frontend/app/components/ui/TextEllipsis/textEllipsis.css
@@ -1,7 +1,7 @@
.textEllipsis {
text-overflow: ellipsis;
overflow: hidden;
- display: inline-block;
+ /* display: inline-block; */
white-space: nowrap;
max-width: 100%;
}
\ No newline at end of file
diff --git a/frontend/app/styles/main.css b/frontend/app/styles/main.css
index fc366bc39..3339c4e48 100644
--- a/frontend/app/styles/main.css
+++ b/frontend/app/styles/main.css
@@ -123,4 +123,15 @@
&:hover {
background-color: $active-blue;
}
+}
+
+.text-dotted-underline {
+ text-decoration: underline dotted !important;
+}
+
+.divider {
+ width: 1px;
+ height: 49px;
+ margin: 0 15px;
+ background-color: $gray-light;
}
\ No newline at end of file