feat(ui) - funnels - issue details

This commit is contained in:
Shekar Siri 2022-06-13 12:32:13 +02:00
parent 936d1f6f6e
commit 4e2bcf26a4
9 changed files with 49 additions and 30 deletions

View file

@ -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;

View file

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

View file

@ -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>

View file

@ -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);

View file

@ -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}>

View file

@ -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();
}
}, [])

View file

@ -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)

View file

@ -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 !== ''
// }
}

View file

@ -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,
})
})
})