diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx
index 0018e319a..b9412de7d 100644
--- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx
+++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx
@@ -7,7 +7,9 @@ import { setCustomSession } from 'App/duck/sessions'
function ClickMapCard({ setCustomSession, visitedEvents }: any) {
const { metricStore } = useStore();
- const onMarkerClick = (s: string) => console.log(s)
+ const onMarkerClick = (s: string, innerText: string) => {
+ metricStore.changeClickMapSearch(s, innerText)
+ }
React.useEffect(() => {
if (metricStore.instance.data.mobsUrl) {
diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
index cb459d7ee..01faed546 100644
--- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
+++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
@@ -30,7 +30,7 @@ interface Props {
function WidgetChart(props: Props) {
const { isWidget = false, metric, isTemplate } = props;
- const { dashboardStore, metricStore } = useStore();
+ const { dashboardStore, metricStore, sessionStore } = useStore();
const _metric: any = metricStore.instance;
const period = dashboardStore.period;
const drillDownPeriod = dashboardStore.drillDownPeriod;
@@ -180,7 +180,6 @@ function WidgetChart(props: Props) {
}
}
if (metricType === CLICKMAP) {
- console.log(props.isPreview)
if (!props.isPreview) {
return (
diff --git a/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx b/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx
index d3a092b49..316bb55e9 100644
--- a/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx
+++ b/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx
@@ -10,6 +10,7 @@ import { debounce } from 'App/utils';
import useIsMounted from 'App/hooks/useIsMounted';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { numberWithCommas } from 'App/utils';
+import { CLICKMAP } from "App/constants/card";
interface Props {
className?: string;
@@ -21,9 +22,9 @@ function WidgetSessions(props: Props) {
const isMounted = useIsMounted();
const [loading, setLoading] = useState(false);
const filteredSessions = getListSessionsBySeries(data, activeSeries);
- const { dashboardStore, metricStore } = useStore();
- const filter = useObserver(() => dashboardStore.drillDownFilter);
- const widget: any = useObserver(() => metricStore.instance);
+ const { dashboardStore, metricStore, sessionStore } = useStore();
+ const filter = dashboardStore.drillDownFilter;
+ const widget = metricStore.instance;
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat('LLL dd, yyyy HH:mm');
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat('LLL dd, yyyy HH:mm');
const [seriesOptions, setSeriesOptions] = useState([{ label: 'All', value: 'all' }]);
@@ -50,30 +51,60 @@ function WidgetSessions(props: Props) {
setLoading(false);
});
};
+ const fetchClickmapSessions = (customFilters: Record
) => {
+ sessionStore.getSessions(customFilters)
+ .then(data => {
+ setData([{ ...data, seriesId: 1 , seriesName: "Clicks" }])
+ })
+ }
const debounceRequest: any = React.useCallback(debounce(fetchSessions, 1000), []);
+ const debounceClickMapSearch = React.useCallback(debounce(fetchClickmapSessions, 1000), [])
const depsString = JSON.stringify(widget.series);
useEffect(() => {
- debounceRequest(widget.metricId, {
- ...filter,
- series: widget.toJsonDrilldown(),
- page: metricStore.sessionsPage,
- limit: metricStore.sessionsPageSize,
- });
- }, [filter.startTimestamp, filter.endTimestamp, filter.filters, depsString, metricStore.sessionsPage]);
+ if (widget.metricType === CLICKMAP && metricStore.clickMapSearch) {
+ const clickFilter = {
+ value: [
+ metricStore.clickMapSearch
+ ],
+ type: "CLICK",
+ operator: "onSelector",
+ isEvent: true,
+ // @ts-ignore
+ "filters": []
+ }
+ const timeRange = {
+ rangeValue: dashboardStore.drillDownPeriod.rangeValue,
+ startDate: dashboardStore.drillDownPeriod.start,
+ endDate: dashboardStore.drillDownPeriod.end,
+ }
+ const customFilter = { ...filter, ...timeRange, filters: [ ...sessionStore.userFilter.filters, clickFilter]}
+ debounceClickMapSearch(customFilter)
+ } else {
+ debounceRequest(widget.metricId, {
+ ...filter,
+ series: widget.toJsonDrilldown(),
+ page: metricStore.sessionsPage,
+ limit: metricStore.sessionsPageSize,
+ });
+ }
+ }, [filter.startTimestamp, filter.endTimestamp, filter.filters, depsString, metricStore.sessionsPage, metricStore.clickMapSearch]);
- return useObserver(() => (
+
+
+ return (
-
Sessions
+
{metricStore.clickMapSearch ? 'Clicks' : 'Sessions'}
+ {metricStore.clickMapLabel ? `"${metricStore.clickMapLabel}" ` : null}
between {startTime} and{' '}
{endTime}{' '}
- {widget.metricType !== 'table' && (
+ {widget.metricType !== 'table' && widget.metricType !== CLICKMAP && (
Filter by Series
@@ -118,7 +149,7 @@ function WidgetSessions(props: Props) {
- ));
+ );
}
const getListSessionsBySeries = (data: any, seriesId: any) => {
diff --git a/frontend/app/mstore/metricStore.ts b/frontend/app/mstore/metricStore.ts
index cc4b9bee2..7f0efdddd 100644
--- a/frontend/app/mstore/metricStore.ts
+++ b/frontend/app/mstore/metricStore.ts
@@ -20,6 +20,9 @@ export default class MetricStore {
sessionsPageSize: number = 10;
listView?: boolean = false
+ clickMapSearch = ''
+ clickMapLabel = ''
+
constructor() {
makeAutoObservable(this);
}
@@ -38,6 +41,11 @@ export default class MetricStore {
this[key] = value;
}
+ changeClickMapSearch(val: string, label: string) {
+ this.clickMapSearch = val
+ this.clickMapLabel = label
+ }
+
merge(object: any) {
Object.assign(this.instance, object);
this.instance.updateKey('hasChanged', true);
@@ -83,12 +91,12 @@ export default class MetricStore {
}
// API Communication
- save(metric: Widget, dashboardId?: string): Promise
{
+ save(metric: Widget): Promise {
const wasCreating = !metric.exists();
this.isSaving = true;
return new Promise((resolve, reject) => {
metricService
- .saveMetric(metric, dashboardId)
+ .saveMetric(metric)
.then((metric: any) => {
const _metric = new Widget().fromJson(metric);
if (wasCreating) {
diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts
index d055a9aa8..553f742b2 100644
--- a/frontend/app/mstore/sessionStore.ts
+++ b/frontend/app/mstore/sessionStore.ts
@@ -94,7 +94,7 @@ export default class SessionStore {
getSessions(filter: any): Promise {
return new Promise((resolve, reject) => {
sessionService
- .getSessions(filter.toJson())
+ .getSessions(filter.toJson?.() || filter)
.then((response: any) => {
resolve({
sessions: response.sessions.map((session: any) => new Session().fromJson(session)),
diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts
index 753691d3d..b7504c4c6 100644
--- a/frontend/app/mstore/types/widget.ts
+++ b/frontend/app/mstore/types/widget.ts
@@ -6,6 +6,7 @@ import Funnelissue from 'App/mstore/types/funnelIssue';
import { issueOptions } from 'App/constants/filterOptions';
import { FilterKey } from 'Types/filter/filterType';
import Period, { LAST_24_HOURS } from 'Types/app/period';
+import { metricService } from "App/services";
export default class Widget {
public static get ID_KEY():string { return "metricId" }
diff --git a/frontend/app/player/web/Screen/Screen.ts b/frontend/app/player/web/Screen/Screen.ts
index 4e6e768bb..ed1cb540a 100644
--- a/frontend/app/player/web/Screen/Screen.ts
+++ b/frontend/app/player/web/Screen/Screen.ts
@@ -176,11 +176,11 @@ export default class Screen {
return this.getElementsFromInternalPoint(this.getInternalViewportCoordinates(point));
}
- getElementBySelector(selector: string): Element | null {
+ getElementBySelector(selector: string) {
if (!selector) return null;
try {
const safeSelector = selector.replace(/:/g, '\\\\3A ').replace(/\//g, '\\/');
- return this.document?.querySelector(safeSelector) || null;
+ return this.document?.querySelector(safeSelector) || null;
} catch (e) {
console.error("Can not select element. ", e)
return null
diff --git a/frontend/app/player/web/addons/TargetMarker.ts b/frontend/app/player/web/addons/TargetMarker.ts
index e20b4c6c4..f063b8dca 100644
--- a/frontend/app/player/web/addons/TargetMarker.ts
+++ b/frontend/app/player/web/addons/TargetMarker.ts
@@ -39,7 +39,7 @@ export default class TargetMarker {
private clickMapOverlay: HTMLDivElement
private clickContainers: HTMLDivElement[] = []
private smallClicks: HTMLDivElement[] = []
- private onMarkerClick: (selector: string) => void
+ private onMarkerClick: (selector: string, innerText: string) => void
static INITIAL_STATE: State = {
markedTargets: null,
activeTargetIndex: 0
@@ -182,7 +182,8 @@ export default class TargetMarker {
border.onclick = (e) => {
e.stopPropagation()
- this.onMarkerClick?.(s.selector)
+ const innerText = el.innerText.length > 25 ? `${el.innerText.slice(0, 20)}...` : el.innerText
+ this.onMarkerClick?.(s.selector, innerText)
this.clickContainers.forEach(container => {
if (container.id === containerId) {
container.style.visibility = "visible"
@@ -201,6 +202,7 @@ export default class TargetMarker {
overlay.onclick = (e) => {
e.stopPropagation()
+ this.onMarkerClick('', '')
this.clickContainers.forEach(container => {
container.style.visibility = "hidden"
})