diff --git a/assets/js/dashboard/historical.js b/assets/js/dashboard/historical.js index 55124fbbbb2d..e19a1e39a968 100644 --- a/assets/js/dashboard/historical.js +++ b/assets/js/dashboard/historical.js @@ -5,7 +5,7 @@ import SiteSwitcher from './site-switcher' import Filters from './filters' import CurrentVisitors from './stats/current-visitors' import VisitorGraph from './stats/visitor-graph' -import Referrers from './stats/referrers' +import Sources from './stats/sources' import Pages from './stats/pages' import Countries from './stats/countries' import Devices from './stats/devices' @@ -35,7 +35,7 @@ export default class Historical extends React.Component {
- +
diff --git a/assets/js/dashboard/realtime.js b/assets/js/dashboard/realtime.js index 5f3a3e912f49..c07b66878d70 100644 --- a/assets/js/dashboard/realtime.js +++ b/assets/js/dashboard/realtime.js @@ -5,7 +5,7 @@ import SiteSwitcher from './site-switcher' import Filters from './filters' import CurrentVisitors from './stats/current-visitors' import VisitorGraph from './stats/visitor-graph' -import Referrers from './stats/referrers' +import Sources from './stats/sources' import Pages from './stats/pages' import Countries from './stats/countries' import Devices from './stats/devices' @@ -34,7 +34,7 @@ export default class Stats extends React.Component {
- +
diff --git a/assets/js/dashboard/stats/sources/index.js b/assets/js/dashboard/stats/sources/index.js new file mode 100644 index 000000000000..716f62689c96 --- /dev/null +++ b/assets/js/dashboard/stats/sources/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import SearchTerms from './search-terms' +import SourceList from './source-list' +import ReferrerList from './referrer-list' + +export default function Sources(props) { + if (props.query.filters.source === 'Google') { + return + } else if (props.query.filters.source) { + return + } else { + return + } +} diff --git a/assets/js/dashboard/stats/referrers.js b/assets/js/dashboard/stats/sources/referrer-list.js similarity index 80% rename from assets/js/dashboard/stats/referrers.js rename to assets/js/dashboard/stats/sources/referrer-list.js index 39bd61b49935..9fc520b8501b 100644 --- a/assets/js/dashboard/stats/referrers.js +++ b/assets/js/dashboard/stats/sources/referrer-list.js @@ -2,11 +2,11 @@ import React from 'react'; import { Link } from 'react-router-dom' import FlipMove from 'react-flip-move'; -import FadeIn from '../fade-in' -import Bar from './bar' -import MoreLink from './more-link' -import numberFormatter from '../number-formatter' -import * as api from '../api' +import FadeIn from '../../fade-in' +import Bar from '../bar' +import MoreLink from '../more-link' +import numberFormatter from '../../number-formatter' +import * as api from '../../api' function LinkOption(props) { if (props.disabled) { @@ -66,19 +66,14 @@ export default class Referrers extends React.Component { renderReferrer(referrer) { const query = new URLSearchParams(window.location.search) - - if (this.props.query.filters.source) { - query.set('referrer', referrer.name) - } else { - query.set('source', referrer.name) - } + query.set('referrer', referrer.name) return (
- + { referrer.name } @@ -96,15 +91,11 @@ export default class Referrers extends React.Component { renderList() { if (this.state.referrers.length > 0) { - const source = this.props.query.filters.source - const keyLabel = source === 'Google' ? 'Search term' : source ? 'Referrer' : 'Source' - const valLabel = this.props.query.period === 'realtime' ? 'Active visitors' : 'Visitors' - return (
- { keyLabel } - { valLabel } + Referrer + { this.label() }
@@ -118,16 +109,12 @@ export default class Referrers extends React.Component { } renderContent() { - const source = this.props.query.filters.source - const title = source === 'Google' ? 'Search terms' : source ? 'Top Referrers' : 'Top Sources' - const endpoint = source ? 'referrers/' + encodeURIComponent(source) : 'referrers' - if (this.state.referrers) { return ( -

{title}

+

Top Referrers

{ this.renderList() } - +
) } diff --git a/assets/js/dashboard/stats/sources/search-terms.js b/assets/js/dashboard/stats/sources/search-terms.js new file mode 100644 index 000000000000..1f73fd53dafa --- /dev/null +++ b/assets/js/dashboard/stats/sources/search-terms.js @@ -0,0 +1,119 @@ +import React from 'react'; +import FadeIn from '../../fade-in' +import Bar from '../bar' +import MoreLink from '../more-link' +import numberFormatter from '../../number-formatter' +import RocketIcon from '../modals/rocket-icon' +import * as api from '../../api' + +export default class SearchTerms extends React.Component { + constructor(props) { + super(props) + this.state = {loading: true} + } + + componentDidMount() { + this.fetchSearchTerms() + } + + componentDidUpdate(prevProps) { + if (this.props.query !== prevProps.query) { + this.setState({loading: true, terms: null}) + this.fetchSearchTerms() + } + } + + fetchSearchTerms() { + api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/referrers/Google`, this.props.query) + .then((res) => this.setState({ + loading: false, + searchTerms: res.search_terms || [], + notConfigured: res.not_configured, + isOwner: res.is_owner + })) + } + + renderSearchTerm(term) { + return ( +
+
+ + + + + { term.name } + + +
+ {numberFormatter(term.count)} +
+ ) + } + + renderList() { + if (this.props.query.filters.goal) { + return ( +
+ +
Sorry, we cannot show which keywords converted best for goal {this.props.query.filters.goal}
+
Google does not share this information
+
+ ) + + } else if (this.state.notConfigured) { + return ( +
+ +
The site is not connected to Google Search Keywords
+
Cannot show search terms
+ {this.state.isOwner && Connect with Google } +
+ ) + } else if (this.state.searchTerms.length > 0) { + const valLabel = this.props.query.period === 'realtime' ? 'Active visitors' : 'Visitors' + + return ( + +
+ Search term + {valLabel} +
+ + {this.state.searchTerms.map(this.renderSearchTerm.bind(this))} +
+ ) + } else { + return ( +
+ +
Could not find any search terms for this period
+
Google Search Console data is sampled and delayed by 24-36h
+
Read more on our documentation
+
+ ) + } + } + + renderContent() { + if (this.state.searchTerms) { + return ( + +

Search Terms

+ { this.renderList() } + +
+ ) + } + } + + render() { + return ( +
+ { this.state.loading &&
} + + { this.renderContent() } + +
+ ) + } +} diff --git a/assets/js/dashboard/stats/sources/source-list.js b/assets/js/dashboard/stats/sources/source-list.js new file mode 100644 index 000000000000..0c7d33929c2a --- /dev/null +++ b/assets/js/dashboard/stats/sources/source-list.js @@ -0,0 +1,108 @@ +import React from 'react'; +import { Link } from 'react-router-dom' +import FlipMove from 'react-flip-move'; + +import FadeIn from '../../fade-in' +import Bar from '../bar' +import MoreLink from '../more-link' +import numberFormatter from '../../number-formatter' +import * as api from '../../api' + +export default class Referrers extends React.Component { + constructor(props) { + super(props) + this.state = {loading: true} + } + + componentDidMount() { + this.fetchReferrers() + if (this.props.timer) this.props.timer.onTick(this.fetchReferrers.bind(this)) + } + + componentDidUpdate(prevProps) { + if (this.props.query !== prevProps.query) { + this.setState({loading: true, referrers: null}) + this.fetchReferrers() + } + } + + showNoRef() { + return this.props.query.period === 'realtime' + } + + fetchReferrers() { + if (this.props.query.filters.goal) { + api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/goal/referrers`, this.props.query) + .then((res) => this.setState({loading: false, referrers: res})) + } else { + api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/referrers`, this.props.query, {show_noref: this.showNoRef()}) + .then((res) => this.setState({loading: false, referrers: res})) + } + } + + renderReferrer(referrer) { + const query = new URLSearchParams(window.location.search) + query.set('source', referrer.name) + + return ( +
+
+ + + + + { referrer.name } + + +
+ {numberFormatter(referrer.count)} +
+ ) + } + + label() { + return this.props.query.period === 'realtime' ? 'Active visitors' : 'Visitors' + } + + renderList() { + if (this.state.referrers.length > 0) { + return ( + +
+ Source + {this.label()} +
+ + + {this.state.referrers.map(this.renderReferrer.bind(this))} + +
+ ) + } else { + return
No data yet
+ } + } + + renderContent() { + if (this.state.referrers) { + return ( + +

Top sources

+ { this.renderList() } + +
+ ) + } + } + + render() { + return ( +
+ { this.state.loading &&
} + + { this.renderContent() } + +
+ ) + } +}