-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
686 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/javascript-node/.devcontainer/base.Dockerfile | ||
|
||
# [Choice] Node.js version: 14, 12, 10 | ||
ARG VARIANT="14-buster" | ||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} | ||
|
||
# [Optional] Uncomment this section to install additional OS packages. | ||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ | ||
# && apt-get -y install --no-install-recommends <your-package-list-here> | ||
|
||
# [Optional] Uncomment if you want to install an additional version of node using nvm | ||
# ARG EXTRA_NODE_VERSION=10 | ||
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" | ||
|
||
# [Optional] Uncomment if you want to install more global node modules | ||
# RUN sudo -u node npm install -g <your-package-list-here> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: | ||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/javascript-node | ||
{ | ||
"name": "Node.js", | ||
"build": { | ||
"dockerfile": "Dockerfile", | ||
// Update 'VARIANT' to pick a Node version: 10, 12, 14 | ||
"args": { "VARIANT": "14" } | ||
}, | ||
|
||
// Set *default* container specific settings.json values on container create. | ||
"settings": { | ||
"terminal.integrated.shell.linux": "/bin/bash" | ||
}, | ||
|
||
// Add the IDs of extensions you want installed when the container is created. | ||
"extensions": [ | ||
"dbaeumer.vscode-eslint" | ||
], | ||
|
||
// Use 'forwardPorts' to make a list of ports inside the container available locally. | ||
// "forwardPorts": [], | ||
|
||
// Use 'postCreateCommand' to run commands after the container is created. | ||
// "postCreateCommand": "yarn install", | ||
|
||
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. | ||
// "remoteUser": "node" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
package-lock.json | ||
config.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# strava-edit-shoes-poc | ||
Client-only proof-of-concept React app using the Strava API to edit shoes on activities. | ||
|
||
## Why? | ||
I use Strava to track my exercise, including runs and walks. I like the Strava feature that tracks your shoe usage. It tracks the shoe miles logged and will remind you when you approach the lifetime miles limit so that you can replace them. | ||
|
||
Not surprisingly, I use running shoes for the runs and walking shoes for the walks. Strava, however, uses the same pair of shoes for both running and walking by default. Seems silly to me, but whatev. | ||
|
||
You can use the UI to change shoes for each workout, but without getting into too much detail... it's annoying. One day I was so annoyed, I decided to learn about the Strava API and build a simple React app to let me edit shoes in an easy-to-use table format. | ||
|
||
I just fire up the dev container in VSCode, run npm start, browse to the app, login to Strava, and edit my activities. | ||
|
||
*Overkill?* Of course! | ||
|
||
*Did I learn something?* Yeah. So that's cool. | ||
|
||
## Instructions for use | ||
NOTE: You must have Docker, Visual Studio Code and the VSCode Remote Containers extension installed in order for these instructions to work. For info about how to install these, see https://code.visualstudio.com/docs/remote/containers. | ||
1. Clone this repo. | ||
1. In VSCode, open the repo in a container. | ||
1. Follow the steps at https://developers.strava.com/docs/getting-started/ under "B. How to Create an account". In this process, note your Client ID and Client Secret. | ||
1. Copy `src/components/config.js.orig` to `src/components/config.js`. In `src/components/config.js`, enter your `config.strava.client_id` and `config.strava.client_secret` values. For `config.strava.redirect_uri`, enter `localhost`. Save the file. | ||
1. In the VSCode terminal, type `npm install`. This will install the node modules. | ||
1. In the VSCode terminal, type `npm start` to start the app. | ||
1. Browse to http://localhost:3000. You should be re-directed to Strava. | ||
1. Login to Strava if asked. | ||
1. You may need to authorize your app. Select all of the checkboxes and click "Authorize". | ||
1. You should be re-directed to the app. | ||
1. Edit the gear for any entry by clicking the Edit link, editing the gear ID, and clicking the Save button. | ||
|
||
## References | ||
* https://www.npmjs.com/package/strava-v3 | ||
* https://developers.strava.com/docs/getting-started/ | ||
* https://developers.strava.com/playground/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "strava-edit-shoes", | ||
"version": "0.1.0", | ||
"private": true, | ||
"dependencies": { | ||
"@testing-library/jest-dom": "^4.2.4", | ||
"@testing-library/react": "^9.3.2", | ||
"@testing-library/user-event": "^7.1.2", | ||
"axios": "^0.20.0", | ||
"bootstrap": "^4.5.2", | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1", | ||
"react-router-dom": "^5.2.0", | ||
"react-scripts": "3.4.3", | ||
"strava-v3": "^2.0.7" | ||
}, | ||
"scripts": { | ||
"start": "react-scripts start", | ||
"build": "react-scripts build", | ||
"test": "react-scripts test", | ||
"eject": "react-scripts eject" | ||
}, | ||
"eslintConfig": { | ||
"extends": "react-app" | ||
}, | ||
"browserslist": { | ||
"production": [ | ||
">0.2%", | ||
"not dead", | ||
"not op_mini all" | ||
], | ||
"development": [ | ||
"last 1 chrome version", | ||
"last 1 firefox version", | ||
"last 1 safari version" | ||
] | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<meta name="theme-color" content="#000000" /> | ||
<meta | ||
name="description" | ||
content="Web site created using create-react-app" | ||
/> | ||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> | ||
<!-- | ||
manifest.json provides metadata used when your web app is installed on a | ||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ | ||
--> | ||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> | ||
<!-- | ||
Notice the use of %PUBLIC_URL% in the tags above. | ||
It will be replaced with the URL of the `public` folder during the build. | ||
Only files inside the `public` folder can be referenced from the HTML. | ||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will | ||
work correctly both with client-side routing and a non-root public URL. | ||
Learn how to configure a non-root public URL by running `npm run build`. | ||
--> | ||
<title>Edit Strava Shoes</title> | ||
</head> | ||
<body> | ||
<noscript>You need to enable JavaScript to run this app.</noscript> | ||
<div id="root"></div> | ||
<!-- | ||
This HTML file is a template. | ||
If you open it directly in the browser, you will see an empty page. | ||
You can add webfonts, meta tags, or analytics to this file. | ||
The build step will place the bundled scripts into the <body> tag. | ||
To begin the development, run `npm start` or `yarn start`. | ||
To create a production bundle, use `npm run build` or `yarn build`. | ||
--> | ||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"short_name": "React App", | ||
"name": "Create React App Sample", | ||
"icons": [ | ||
{ | ||
"src": "favicon.ico", | ||
"sizes": "64x64 32x32 24x24 16x16", | ||
"type": "image/x-icon" | ||
}, | ||
{ | ||
"src": "logo192.png", | ||
"type": "image/png", | ||
"sizes": "192x192" | ||
}, | ||
{ | ||
"src": "logo512.png", | ||
"type": "image/png", | ||
"sizes": "512x512" | ||
} | ||
], | ||
"start_url": ".", | ||
"display": "standalone", | ||
"theme_color": "#000000", | ||
"background_color": "#ffffff" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# https://www.robotstxt.org/robotstxt.html | ||
User-agent: * | ||
Disallow: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.App { | ||
text-align: center; | ||
} | ||
|
||
.App-logo { | ||
height: 40vmin; | ||
pointer-events: none; | ||
} | ||
|
||
@media (prefers-reduced-motion: no-preference) { | ||
.App-logo { | ||
animation: App-logo-spin infinite 20s linear; | ||
} | ||
} | ||
|
||
.App-header { | ||
background-color: #282c34; | ||
min-height: 100vh; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
font-size: calc(10px + 2vmin); | ||
color: white; | ||
} | ||
|
||
.App-link { | ||
color: #61dafb; | ||
} | ||
|
||
@keyframes App-logo-spin { | ||
from { | ||
transform: rotate(0deg); | ||
} | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React from 'react'; | ||
import { BrowserRouter as Router, Route, Link } from "react-router-dom"; | ||
import "bootstrap/dist/css/bootstrap.min.css"; | ||
|
||
import EditActivity from "./components/edit-activity.component"; | ||
import ActivitiesList from "./components/activities-list.component"; | ||
import AuthorizationRedirect from "./components/authorization-redirect.component"; | ||
|
||
import logo from "./logo.svg"; | ||
|
||
function App() { | ||
return ( | ||
<Router> | ||
<div className="container"> | ||
<nav className="navbar navbar-expand-lg navbar-light bg-light"> | ||
<a className="navbar-brand" href="/" > | ||
<img src={logo} width="30" heigth="30" alt="Strava Edit Shoes" /> | ||
</a> | ||
<Link to="/" className="navbar-brand">Strava Edit Shoes</Link> | ||
<div className="collapse navbar-collapse"> | ||
<ul className="navbar-nav mr-auto"> | ||
<li className="navbar-item"> | ||
</li> | ||
</ul> | ||
</div> | ||
</nav> | ||
<Route path="/" exact component={ActivitiesList} /> | ||
<Route path="/authorization_redirect" exact component={AuthorizationRedirect} /> | ||
<Route path="/edit/:id" component={EditActivity} /> | ||
</div> | ||
</Router> | ||
); | ||
} | ||
|
||
export default App; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import App from './App'; | ||
|
||
test('renders learn react link', () => { | ||
const { getByText } = render(<App />); | ||
const linkElement = getByText(/learn react/i); | ||
expect(linkElement).toBeInTheDocument(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import React, { Component } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import axios from 'axios'; | ||
var strava = require('strava-v3') | ||
var config = require('../config'); | ||
|
||
axios.defaults.baseURL = 'https://www.strava.com/api/v3/'; // the prefix of the URL | ||
|
||
const Activity = props => ( | ||
<tr> | ||
<td>{props.activity.name}</td> | ||
<td>{props.activity.gear_id}</td> | ||
<td>{props.activity.start_date}</td> | ||
<td> | ||
<Link to={"/edit/"+props.activity.id+"?access_token="+props.activity.access_token}>Edit</Link> | ||
</td> | ||
</tr> | ||
) | ||
|
||
export default class ActivitiesList extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = {activities: []}; | ||
} | ||
|
||
componentDidMount() { | ||
var access_token = new URLSearchParams(this.props.location.search).get("access_token") | ||
axios.get('/athlete/activities', { | ||
headers: { | ||
'authorization': 'Bearer ' + access_token | ||
} | ||
}) | ||
.then(response => { | ||
console.log(response.data); | ||
this.setState({activities: response.data}); | ||
}) | ||
.catch(function(error) { | ||
console.log(error); | ||
}) | ||
} | ||
|
||
activityList() { | ||
var access_token = new URLSearchParams(this.props.location.search).get("access_token") | ||
return this.state.activities.map(function(currentActivity, i) { | ||
currentActivity["access_token"] = access_token; | ||
return <Activity activity={currentActivity} key={i} />; | ||
}) | ||
} | ||
|
||
oAuthRedirect() { | ||
if (!(new URLSearchParams(this.props.location.search).has("access_token"))) { | ||
strava.config({ | ||
"client_id" : config.strava.client_id, | ||
"client_secret" : config.strava.client_secret, | ||
"redirect_uri" : config.strava.redirect_uri | ||
}); | ||
|
||
// Generates the url to have full access | ||
var url = strava.oauth.getRequestAccessURL({ | ||
scope:"profile:read_all,activity:read_all,activity:write" | ||
}); | ||
// We have to grab the code manually in the browser and then copy/paste it into strava_config as "access_token" | ||
// console.log('Connect to the following url and copy the code: ' + url); | ||
return window.location.href = url; | ||
} | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<h3>Activity List</h3> | ||
<table className="table table-striped" style={{marginTop: 20 }}> | ||
<thead> | ||
<tr> | ||
<th>Name</th> | ||
<th>Gear ID</th> | ||
<th>Start Date</th> | ||
<th >Actions</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{ this.activityList() } | ||
{ this.oAuthRedirect() } | ||
</tbody> | ||
</table> | ||
</div> | ||
) | ||
} | ||
} |
Oops, something went wrong.