feat(ui) - funnels - issue details
This commit is contained in:
parent
936d1f6f6e
commit
4e2bcf26a4
9 changed files with 49 additions and 30 deletions
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
|
||||
interface Props {
|
||||
|
||||
}
|
||||
function FunnelIssueModal(props: Props) {
|
||||
const { hideModal } = useModal();
|
||||
return (
|
||||
<div style={{ width: '85vw', maxWidth: '1200px' }}>
|
||||
<div
|
||||
className="border-r shadow p-4 h-screen"
|
||||
style={{ backgroundColor: '#FAFAFA', zIndex: 999, width: '100%' }}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FunnelIssueModal;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './FunnelIssueModal';
|
||||
|
|
@ -8,6 +8,7 @@ import FunnelIssuesList from '../FunnelIssuesList';
|
|||
import { DateTime } from 'luxon';
|
||||
import { debounce } from 'App/utils';
|
||||
import useIsMounted from 'App/hooks/useIsMounted'
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
|
||||
function FunnelIssues() {
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
|
|
@ -55,8 +56,12 @@ function FunnelIssues() {
|
|||
<Loader loading={loading}>
|
||||
<NoContent
|
||||
show={!loading && data.issues.length === 0}
|
||||
title="No issues found."
|
||||
animatedIcon="empty-state"
|
||||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedSVG name={ICONS.NO_RESULTS} size="170" />
|
||||
<div className="mt-6 text-2xl">No issues found</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<FunnelIssuesList issues={data.issues} />
|
||||
</NoContent>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ function FunnelIssuesList(props: Props) {
|
|||
const { funnelStore } = useStore();
|
||||
const issuesSort = useObserver(() => funnelStore.issuesSort);
|
||||
const issuesFilter = useObserver(() => funnelStore.issuesFilter.map((issue: any) => issue.value));
|
||||
// const issues = useObserver(() => funnelStore.issues);
|
||||
|
||||
let filteredIssues = useObserver(() => issuesFilter.length > 0 ? issues.filter((issue: any) => issuesFilter.includes(issue.type)) : issues);
|
||||
filteredIssues = useObserver(() => issuesSort.sort ? filteredIssues.slice().sort((a: { [x: string]: number; }, b: { [x: string]: number; }) => a[issuesSort.sort] - b[issuesSort.sort]): filteredIssues);
|
||||
filteredIssues = useObserver(() => issuesSort.order === 'desc' ? filteredIssues.reverse() : filteredIssues);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||
import cn from 'classnames';
|
||||
import { Icon, TextEllipsis } from 'UI';
|
||||
import FunnelIssueGraph from '../FunnelIssueGraph';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import FunnelIssueModal from '../FunnelIssueModal';
|
||||
|
||||
interface Props {
|
||||
issue: any;
|
||||
|
|
@ -9,8 +11,9 @@ interface Props {
|
|||
}
|
||||
function FunnelIssuesListItem(props) {
|
||||
const { issue, inDetails = false } = props;
|
||||
const { showModal } = useModal();
|
||||
const onClick = () => {
|
||||
// console.log('onClick', issue);
|
||||
showModal(<FunnelIssueModal />, { right: true });
|
||||
}
|
||||
return (
|
||||
<div className={cn('flex flex-col bg-white w-full rounded border relative hover:bg-active-blue', { 'cursor-pointer bg-hover' : !inDetails })} onClick={!inDetails ? onClick : () => null}>
|
||||
|
|
|
|||
|
|
@ -24,11 +24,9 @@ function WidgetView(props: Props) {
|
|||
const [expanded, setExpanded] = useState(!metricId || metricId === 'create');
|
||||
|
||||
React.useEffect(() => {
|
||||
if (metricId && metricId !== 'create' && (!widget || !widget.exists())) {
|
||||
if (metricId && metricId !== 'create') {
|
||||
metricStore.fetch(metricId);
|
||||
}
|
||||
|
||||
if (metricId === 'create') {
|
||||
} else if (metricId === 'create') {
|
||||
metricStore.init();
|
||||
}
|
||||
}, [])
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ export default class MetricStore implements IMetricStore {
|
|||
|
||||
// State Actions
|
||||
init(metric?: IWidget|null) {
|
||||
console.log('metric', metric);
|
||||
// const _metric = new Widget().fromJson(sampleJsonErrors)
|
||||
// this.instance.update(metric || _metric)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// import Filter, { IFilter } from "./filter"
|
||||
import FunnelStage from './funnelStage'
|
||||
|
||||
export interface IFunnel {
|
||||
|
|
@ -22,27 +21,15 @@ export default class Funnel implements IFunnel {
|
|||
}
|
||||
|
||||
fromJSON(json: any) {
|
||||
const firstStage = json.stages[0]
|
||||
const lastStage = json.stages[json.stages.length - 1]
|
||||
this.lostConversions = json.totalDropDueToIssues
|
||||
this.conversionImpact = this.lostConversions ? Math.round((this.lostConversions / firstStage.sessionsCount) * 100) : 0;
|
||||
this.stages = json.stages ? json.stages.map((stage: any) => new FunnelStage().fromJSON(stage)) : []
|
||||
this.affectedUsers = firstStage.usersCount ? firstStage.usersCount - lastStage.usersCount : 0;
|
||||
if (json.stages.length >= 1) {
|
||||
const firstStage = json.stages[0]
|
||||
const lastStage = json.stages[json.stages.length - 1]
|
||||
this.lostConversions = json.totalDropDueToIssues
|
||||
this.conversionImpact = this.lostConversions ? Math.round((this.lostConversions / firstStage.sessionsCount) * 100) : 0;
|
||||
this.stages = json.stages ? json.stages.map((stage: any) => new FunnelStage().fromJSON(stage)) : []
|
||||
this.affectedUsers = firstStage.usersCount ? firstStage.usersCount - lastStage.usersCount : 0;
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
// toJSON(): any {
|
||||
// return {
|
||||
// // funnelId: this.funnelId,
|
||||
// // name: this.name,
|
||||
// // filter: this.filter.toJson(),
|
||||
// // sessionsCount: this.sessionsCount,
|
||||
// // conversionRate: this.conversionRate,
|
||||
// }
|
||||
// }
|
||||
|
||||
// exists(): boolean {
|
||||
// return this.funnelId !== ''
|
||||
// }
|
||||
}
|
||||
|
|
@ -217,8 +217,10 @@ export default class Widget implements IWidget {
|
|||
fetchIssues(filter: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
metricService.fetchIssues(filter).then((response: any) => {
|
||||
const significantIssues = response.issues.significant ? response.issues.significant.map((issue: any) => new Funnelissue().fromJSON(issue)) : []
|
||||
const insignificantIssues = response.issues.insignificant ? response.issues.insignificant.map((issue: any) => new Funnelissue().fromJSON(issue)) : []
|
||||
resolve({
|
||||
issues: response.issues.insignificant ? response.issues.insignificant.map((issue: any) => new Funnelissue().fromJSON(issue)) : [],
|
||||
issues: significantIssues.length > 0 ? significantIssues : insignificantIssues,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue