Stats.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import React, { Component } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { bindActionCreators } from 'redux';
  4. import { connect } from 'react-redux';
  5. import Router from 'next/router';
  6. import styled from 'styled-components';
  7. import axios from 'axios';
  8. import cookie from 'js-cookie';
  9. import StatsError from './StatsError';
  10. import StatsHead from './StatsHead';
  11. import StatsCharts from './StatsCharts';
  12. import PageLoading from '../PageLoading';
  13. import Button from '../Button';
  14. import { showPageLoading } from '../../actions';
  15. const Wrapper = styled.div`
  16. width: 1200px;
  17. max-width: 95%;
  18. display: flex;
  19. flex-direction: column;
  20. align-items: stretch;
  21. margin: 40px 0;
  22. `;
  23. const TitleWrapper = styled.div`
  24. display: flex;
  25. justify-content: space-between;
  26. align-items: center;
  27. `;
  28. const Title = styled.h2`
  29. font-size: 24px;
  30. font-weight: 300;
  31. a {
  32. color: #2196f3;
  33. text-decoration: none;
  34. border-bottom: 1px dotted transparent;
  35. :hover {
  36. border-bottom-color: #2196f3;
  37. }
  38. }
  39. @media only screen and (max-width: 768px) {
  40. font-size: 18px;
  41. }
  42. `;
  43. const TitleTarget = styled.p`
  44. font-size: 14px;
  45. text-align: right;
  46. color: #333;
  47. @media only screen and (max-width: 768px) {
  48. font-size: 11px;
  49. }
  50. `;
  51. const Content = styled.div`
  52. display: flex;
  53. flex: 1 1 auto;
  54. flex-direction: column;
  55. background-color: white;
  56. border-radius: 12px;
  57. box-shadow: 0 6px 30px rgba(50, 50, 50, 0.2);
  58. `;
  59. const ButtonWrapper = styled.div`
  60. align-self: center;
  61. margin: 64px 0;
  62. `;
  63. class Stats extends Component {
  64. constructor() {
  65. super();
  66. this.state = {
  67. error: false,
  68. loading: true,
  69. period: 'lastDay',
  70. stats: null,
  71. };
  72. this.changePeriod = this.changePeriod.bind(this);
  73. this.goToHomepage = this.goToHomepage.bind(this);
  74. }
  75. componentDidMount() {
  76. const { id } = this.props;
  77. if (!id) return null;
  78. return axios
  79. .get(`/api/url/stats?id=${id}`, { headers: { Authorization: cookie.get('token') } })
  80. .then(({ data }) =>
  81. this.setState({
  82. stats: data,
  83. loading: false,
  84. error: !data,
  85. })
  86. )
  87. .catch(() => this.setState({ error: true, loading: false }));
  88. }
  89. changePeriod(e) {
  90. e.preventDefault();
  91. const { period } = e.currentTarget.dataset;
  92. this.setState({ period });
  93. }
  94. goToHomepage(e) {
  95. e.preventDefault();
  96. this.props.showPageLoading();
  97. Router.push('/');
  98. }
  99. render() {
  100. const { error, loading, period, stats } = this.state;
  101. const { isAuthenticated, id } = this.props;
  102. if (!isAuthenticated) return <StatsError text="You need to login to view stats." />;
  103. if (!id || error) return <StatsError />;
  104. if (loading) return <PageLoading />;
  105. return (
  106. <Wrapper>
  107. <TitleWrapper>
  108. <Title>
  109. Stats for:{' '}
  110. <a href={stats.shortUrl} title="Short URL">
  111. {stats.shortUrl.replace(/https?:\/\//, '')}
  112. </a>
  113. </Title>
  114. <TitleTarget>
  115. {stats.target.length > 80
  116. ? `${stats.target
  117. .split('')
  118. .slice(0, 80)
  119. .join('')}...`
  120. : stats.target}
  121. </TitleTarget>
  122. </TitleWrapper>
  123. <Content>
  124. <StatsHead total={stats.total} period={period} changePeriod={this.changePeriod} />
  125. <StatsCharts stats={stats[period]} period={period} />
  126. </Content>
  127. <ButtonWrapper>
  128. <Button icon="arrow-left" onClick={this.goToHomepage}>
  129. Back to homepage
  130. </Button>
  131. </ButtonWrapper>
  132. </Wrapper>
  133. );
  134. }
  135. }
  136. Stats.propTypes = {
  137. isAuthenticated: PropTypes.bool.isRequired,
  138. id: PropTypes.string.isRequired,
  139. showPageLoading: PropTypes.func.isRequired,
  140. };
  141. const mapStateToProps = ({ auth: { isAuthenticated } }) => ({ isAuthenticated });
  142. const mapDispatchToProps = dispatch => ({
  143. showPageLoading: bindActionCreators(showPageLoading, dispatch),
  144. });
  145. export default connect(mapStateToProps, mapDispatchToProps)(Stats);