feat(ui) - funnels - issue details

This commit is contained in:
Shekar Siri 2022-06-13 14:04:16 +02:00
parent 4e2bcf26a4
commit b26f2e87bf
5 changed files with 63 additions and 39 deletions

View file

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { useStore } from 'App/mstore';
import { useObserver } from 'mobx-react-lite';
import { Loader } from 'UI';
@ -6,23 +6,25 @@ import FunnelIssuesListItem from '../FunnelIssuesListItem';
import SessionItem from 'App/components/shared/SessionItem/SessionItem';
interface Props {
funnelId: string;
issueId: string;
}
function FunnelIssueDetails(props: Props) {
const { funnelStore } = useStore();
const { funnelId, issueId } = props;
const funnel = useObserver(() => funnelStore.instance);
const funnelIssue = useObserver(() => funnelStore.issueInstance);
const loading = useObserver(() => funnelStore.isLoadingIssues);
const { dashboardStore, metricStore } = useStore();
const { issueId } = props;
const filter = useObserver(() => dashboardStore.drillDownFilter);
const widget = useObserver(() => metricStore.instance);
const [loading, setLoading] = useState(false);
const [funnelIssue, setFunnelIssue] = useState<any>(null);
const [sessions, setSessions] = useState<any>([]);
useEffect(() => {
if (!funnel || !funnel.exists()) {
// funnelStore.fetchFunnel(props.funnelId);
funnelStore.fetchFunnel('143');
}
funnelStore.fetchIssue(funnelId, issueId);
setLoading(true);
widget.fetchIssue(widget.metricId, issueId, filter).then((resp: any) => {
setFunnelIssue(resp.issue);
setSessions(resp.sessions);
}).finally(() => {
setLoading(false);
});
}, []);
return (
@ -33,7 +35,7 @@ function FunnelIssueDetails(props: Props) {
/>}
<div className="mt-6">
{funnelIssue && funnelIssue.sessions.map(session => (
{sessions.map((session: any) => (
<SessionItem key={session.id} session={session} />
))}
</div>

View file

@ -2,11 +2,13 @@ import React from 'react';
import { withRouter } from 'react-router-dom';
import { useStore } from 'App/mstore';
import { useModal } from 'App/components/Modal';
import FunnelIssueDetails from '../FunnelIssueDetails';
interface Props {
issueId: string;
}
function FunnelIssueModal(props: Props) {
const { issueId } = props;
const { hideModal } = useModal();
return (
<div style={{ width: '85vw', maxWidth: '1200px' }}>
@ -14,6 +16,7 @@ function FunnelIssueModal(props: Props) {
className="border-r shadow p-4 h-screen"
style={{ backgroundColor: '#FAFAFA', zIndex: 999, width: '100%' }}
>
<FunnelIssueDetails issueId={issueId} />
</div>
</div>
);

View file

@ -13,7 +13,7 @@ function FunnelIssuesListItem(props) {
const { issue, inDetails = false } = props;
const { showModal } = useModal();
const onClick = () => {
showModal(<FunnelIssueModal />, { right: true });
showModal(<FunnelIssueModal issueId={issue.issueId} />, { 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}>
@ -30,49 +30,49 @@ function FunnelIssuesListItem(props) {
</div>
{inDetails && (
<div className="flex-1 overflow-hidden">
<div className="text-lg font-medium mb-2 capitalize">{issue.title}</div>
<div className="text-xl whitespace-nowrap">
<TextEllipsis text={issue.contextString} />
<div className="flex-1 overflow-hidden">
<div className="text-lg font-medium mb-2 capitalize">{issue.title}</div>
<div className="text-xl whitespace-nowrap">
<TextEllipsis text={issue.contextString} />
</div>
</div>
</div>
)}
{!inDetails && (
<div className="flex-1 overflow-hidden">
<div className="text-xl mb-2 capitalize">{issue.title}</div>
<div className="text-sm color-gray-medium whitespace-nowrap leading-none">
<TextEllipsis text={issue.contextString} />
<div className="flex-1 overflow-hidden">
<div className="text-xl mb-2 capitalize">{issue.title}</div>
<div className="text-sm color-gray-medium whitespace-nowrap leading-none">
<TextEllipsis text={issue.contextString} />
</div>
</div>
</div>
)}
<div className="text-center text-sm ml-10 flex-shrink-0">
<div className="text-xl mb-2">{issue.affectedUsers}</div>
<div className="color-gray-medium leading-none">Affected Users</div>
<div className="text-xl mb-2">{issue.affectedUsers}</div>
<div className="color-gray-medium leading-none">Affected Users</div>
</div>
<div className="text-center text-sm ml-10 flex-shrink-0">
<div className="text-xl mb-2 color-red">{issue.conversionImpact}<span className="text-sm ml-1">%</span></div>
<div className="color-gray-medium leading-none">Conversion Impact</div>
<div className="text-xl mb-2 color-red">{issue.conversionImpact}<span className="text-sm ml-1">%</span></div>
<div className="color-gray-medium leading-none">Conversion Impact</div>
</div>
<div className="text-center text-sm ml-10 flex-shrink-0">
<div className="text-xl mb-2">{issue.lostConversions}</div>
<div className="color-gray-medium leading-none">Lost Conversions</div>
<div className="text-xl mb-2">{issue.lostConversions}</div>
<div className="color-gray-medium leading-none">Lost Conversions</div>
</div>
</div>
{inDetails && (
<div className="flex items-center px-6 py-4 justify-between border-t">
<FunnelIssueGraph issue={issue} />
<div className="flex items-center">
<Info label="Unaffected sessions" color="rgba(217, 219, 238, 0.7)" />
<Info label="Affected sessions" color="rgba(238, 238, 238, 0.7)" />
<Info label="Conversion Lost" color="rgba(204, 0, 0, 0.26)" />
</div>
<FunnelIssueGraph issue={issue} />
<div className="flex items-center">
<Info label="Unaffected sessions" color="rgba(217, 219, 238, 0.7)" />
<Info label="Affected sessions" color="rgba(238, 238, 238, 0.7)" />
<Info label="Conversion Lost" color="rgba(204, 0, 0, 0.26)" />
</div>
</div>
)}
</div>
</div>
);
}

View file

@ -225,4 +225,17 @@ export default class Widget implements IWidget {
})
})
}
fetchIssue(funnelId: any, issueId: any, params: any): Promise<any> {
return new Promise((resolve, reject) => {
metricService.fetchIssue(funnelId, issueId, params).then((response: any) => {
resolve({
issue: new Funnelissue().fromJSON(response.issue),
sessions: response.sessions.map((s: any) => new Session().fromJson(s)),
})
}).catch((error: any) => {
reject(error)
})
})
}
}

View file

@ -108,4 +108,10 @@ export default class MetricService implements IMetricService {
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || {});
}
fetchIssue(funnelId: string, issueId: string, params: any): Promise<any> {
return this.client.post(`/funnels/${funnelId}/issues/${issueId}/sessions`, params)
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || {});
}
}