Skip to content

Commit

Permalink
Merge pull request #115 from ClickPop/release/1.0.0-alpha.8
Browse files Browse the repository at this point in the history
Version 1.0.0-alpha.8
  • Loading branch information
seanmetzgar authored Dec 9, 2020
2 parents 80a6f45 + eeaa980 commit bfee054
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ yarn-debug.log*
yarn-error.log*

.eslintcache
.env
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "backtalk-ui",
"version": "1.0.0-alpha.7",
"version": "1.0.0-alpha.8",
"private": true,
"dependencies": {
"axios": "^0.20.0",
Expand All @@ -16,6 +16,7 @@
"react-dom": "^16.13.1",
"react-feather": "^2.0.9",
"react-gtm-module": "^2.0.11",
"react-map-gl": "^5.2.10",
"react-moment": "^1.0.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
Expand Down
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import packageJson from '../package.json';
import TagManager from 'react-gtm-module';
import { PasswordResetStart } from './views/PasswordResetStart';
import { PasswordReset } from './views/PasswordReset';
import { Admin } from './views/Admin';
import { ShareResponses } from './views/ShareResponses';

if (process.env.NODE_ENV === 'production') {
Expand Down Expand Up @@ -93,6 +94,7 @@ const App = () => {
component={FirstSurvey}
/>
<ProtectedRoute exact path="/dashboard" component={Dashboard} />
<ProtectedRoute exact path="/admin" component={Admin} />
<ProtectedRoute
exact
path="/responses/:hash"
Expand Down
41 changes: 41 additions & 0 deletions src/components/ResponseMap.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from 'react';
import ReactMapGL, { Marker } from 'react-map-gl';
const apiKey = process.env.REACT_APP_MAPBOX_KEY;

export const ResponseMap = ({ responses }) => {
const [latitude, longitude] = responses.filter((r) => r.geo)[0]?.geo?.ll;
const [viewport, setViewport] = useState({
width: '100%',
height: 200,
latitude,
longitude,
zoom: 1,
});

return (
<div className="mb-4 rounded-3 overflow-hidden">
<ReactMapGL
mapboxApiAccessToken={apiKey}
{...viewport}
mapStyle="mapbox://styles/mapbox/streets-v8"
onViewportChange={(nextViewport) => setViewport(nextViewport)}
>
{responses
.filter((r) => r.geo && r.geo.ll)
.map((response) => (
<Marker
key={response.id}
latitude={response.geo.ll[0]}
longitude={response.geo.ll[1]}
offsetLeft={viewport.zoom - 10}
offsetTop={viewport.zoom - 10}
>
<span role="img" aria-label="reponse map pin">
📍
</span>
</Marker>
))}
</ReactMapGL>
</div>
);
};
1 change: 1 addition & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './scss/index.scss';
import 'mapbox-gl/dist/mapbox-gl.css';
import App from './App';
import 'bootstrap';
import 'popper.js';
Expand Down
104 changes: 104 additions & 0 deletions src/views/Admin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as axios from 'axios';
import React, { useContext, useEffect, useState } from 'react';
import Moment from 'react-moment';
import { Card } from '../components/Card';
import { context } from '../context/Context';

export const Admin = () => {
const [view, setView] = useState(null);
const [users, setUsers] = useState([]);
const [surveys, setSurveys] = useState([]);
const [userCount, setUserCount] = useState(0);
const [surveyCount, setSurveyCount] = useState(0);
const [responseCount, setResponseCount] = useState(0);
const { state } = useContext(context);
useEffect(() => {
const fetchData = async () => {
const totalUsers = await axios.get('/api/v1/admin/users', {
headers: { Authorization: `Bearer ${state.token}` },
});

const totalSurveys = await axios.get('/api/v1/admin/surveys', {
headers: { Authorization: `Bearer ${state.token}` },
});

setUserCount(totalUsers.data.results.length);
setSurveyCount(totalSurveys.data.results.length);
setResponseCount(
totalSurveys.data.results.reduce(
(sum, survey) => survey.Responses.length + sum,
0,
),
);
setUsers(totalUsers.data.results);
setSurveys(totalSurveys.data.results);
};

fetchData();
}, [state.token]);

return (
<div className="container">
<div className="row">
<div className="col-12 order-sm-2 col-sm-6 col-lg-4">
<h2 className="h3 mb-3">Show me</h2>
{users.length > 0 && (
<div>
<p
className="card-text"
onClick={() => setView('users')}
style={{ cursor: 'pointer' }}
>
Users: {userCount}
</p>
<p
className="card-text"
onClick={() => setView('surveys')}
style={{ cursor: 'pointer' }}
>
Surveys: {surveyCount}
</p>
<p className="card-text">Responses: {responseCount}</p>
</div>
)}
</div>
<div className="col-12 order-sm-1 col-sm-6 col-lg-8 pr-sm-4">
<h1 className="mb-4">Results</h1>
{view === 'users' &&
users &&
users.map((user) => (
<Card key={user.id} title={user.name} className="mb-2">
<p className="card-text">Email: {user.email}</p>
<p className="text-muted">
<strong>
Sign-up Date:{' '}
<Moment format="MMM D, YYYY">{user.createdAt}</Moment>{' '}
<Moment format="h:mm a">{user.createdAt}</Moment>
</strong>
</p>
</Card>
))}
{view === 'surveys' &&
surveys &&
surveys.map((survey) => (
<Card key={survey.id} title={survey.title} className="mb-2">
<p className="card-text">
Questions: {survey.Questions.length}
</p>
<p className="card-text">
Responses: {survey.Responses.length}
</p>
<p className="text-muted">
<strong>
Created At:{' '}
<Moment format="MMM D, YYYY">{survey.createdAt}</Moment>{' '}
<Moment format="h:mm a">{survey.createdAt}</Moment>
</strong>
</p>
</Card>
))}
</div>
</div>
</div>
);
};
6 changes: 6 additions & 0 deletions src/views/Changelog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const Changelog = () => {
A list of all the ways Backtalk is making it easier to get the
answers you need, quickly.
</p>
<ChangelogEntry
title="Response Map"
date="December 9, 2020"
description="We added a map so you can get a better idea of where your responses are coming from."
/>

<ChangelogEntry
title="Click to Copy"
date="December 6, 2020"
Expand Down
2 changes: 2 additions & 0 deletions src/views/Responses.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import anonymousNickname from '../helpers/anonymousNickname';
import { EditInPlaceInput } from '../components/EditInPlaceInput';
import { ResponseCard } from '../components/ResponseCard';
import { CopyLink } from '../components/CopyLink';
import { ResponseMap } from '../components/ResponseMap';

export const Responses = () => {
const params = useParams();
Expand Down Expand Up @@ -291,6 +292,7 @@ export const Responses = () => {
<div className="row">
<div className="col-12 order-sm-2 col-sm-6 col-lg-4">
<div className="mb-4">
{responses?.length > 0 && <ResponseMap responses={responses} />}
<h3 className="h5">Share Survey</h3>
<CopyLink
to={`/survey/${params.hash}`}
Expand Down
Loading

0 comments on commit bfee054

Please sign in to comment.