mirror of
https://github.com/jcreek/BankStatementAnalyser.git
synced 2026-07-12 18:43:49 +00:00
feat(*): Add sample chart and sheets data
This commit is contained in:
Generated
+19161
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "BankStatementAnalyser",
|
||||||
|
"version": "1.5.0",
|
||||||
|
"description": "A tiny web app to display graphs and stats from a bank statement/csv/google sheet.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --config webpack.prod.js",
|
||||||
|
"dev": "webpack serve --hot --config webpack.dev.js",
|
||||||
|
"lint": "eslint --ignore-path .eslintignore --ext .js,.ts ."
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jcreek/BankStatementAnalyser"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "jcreek",
|
||||||
|
"license": "GNU General Public License v3.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.18.5",
|
||||||
|
"@babel/preset-env": "^7.18.2",
|
||||||
|
"@babel/preset-typescript": "^7.17.12",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||||
|
"@typescript-eslint/parser": "^5.28.0",
|
||||||
|
"babel-loader": "^8.2.5",
|
||||||
|
"css-loader": "^6.7.1",
|
||||||
|
"eslint": "^8.17.0",
|
||||||
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"sass": "^1.52.3",
|
||||||
|
"sass-loader": "^13.0.0",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"typescript": "^4.7.3",
|
||||||
|
"webpack": "^5.73.0",
|
||||||
|
"webpack-cli": "^4.10.0",
|
||||||
|
"webpack-dev-server": "^4.9.2",
|
||||||
|
"webpack-webmanifest-loader": "^2.0.2",
|
||||||
|
"workbox-cli": "^6.5.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/chart.js": "^2.9.37",
|
||||||
|
"chart.js": "^4.1.0",
|
||||||
|
"html-webpack-plugin": "^5.5.0",
|
||||||
|
"react-dev-utils": "^12.0.1",
|
||||||
|
"webpack-manifest-plugin": "^5.0.0",
|
||||||
|
"webpack-merge": "^5.8.0",
|
||||||
|
"workbox-navigation-preload": "^6.5.4",
|
||||||
|
"workbox-precaching": "^6.5.4",
|
||||||
|
"workbox-routing": "^6.5.4",
|
||||||
|
"workbox-strategies": "^6.5.4",
|
||||||
|
"workbox-webpack-plugin": "^6.5.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import loadServiceWorker from './loadServiceWorker';
|
||||||
|
import Chart from 'chart.js/auto';
|
||||||
|
|
||||||
|
require('./assets/favicon.ico');
|
||||||
|
require('./assets/android-chrome-192x192.png');
|
||||||
|
require('./assets/android-chrome-512x512.png');
|
||||||
|
require('./assets/apple-touch-icon.png');
|
||||||
|
require('./assets/favicon-16x16.png');
|
||||||
|
require('./assets/favicon-32x32.png');
|
||||||
|
require('./styles/main.scss');
|
||||||
|
require('./styles/buttons.scss');
|
||||||
|
require('./styles/modal.scss');
|
||||||
|
require('./styles/spinner.scss');
|
||||||
|
|
||||||
|
const ctx: HTMLCanvasElement = <HTMLCanvasElement>document.getElementById('myChart');
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
||||||
|
datasets: [{
|
||||||
|
label: '# of Votes',
|
||||||
|
data: [12, 19, 3, 5, 2, 3],
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
loadServiceWorker();
|
||||||
|
}
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-EZ2WT7NQMK"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-EZ2WT7NQMK');
|
||||||
|
</script> -->
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="A tiny web app to display graphs and stats from a bank statement/csv/google sheet.">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<link rel="manifest" href="<%= require('../src/assets/manifest.webmanifest') %>" />
|
||||||
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="topbar-container">
|
||||||
|
<div class="topbar-items"><h1><a href="/">Bank Statement Analyser</a></h1></div>
|
||||||
|
<p id="install-app-btn-container" class="topbar-items">
|
||||||
|
<button id="install-offline-app" class="button button-black" role="button">
|
||||||
|
<span>Install the app (you can even use it offline!)</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<p>Sheets API Quickstart</p>
|
||||||
|
|
||||||
|
<!--Add buttons to initiate auth sequence and sign out-->
|
||||||
|
<button id="authorize_button" onclick="handleAuthClick()">Authorize</button>
|
||||||
|
<button id="signout_button" onclick="handleSignoutClick()">Sign Out</button>
|
||||||
|
|
||||||
|
<pre id="content" style="white-space: pre-wrap;"></pre>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<canvas id="myChart"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<footer class="footer-container">
|
||||||
|
<hr>
|
||||||
|
<span class="footer-items">Copyright © 2022 Josh Creek</span>
|
||||||
|
<!-- <span> | </span> -->
|
||||||
|
<!-- <span class="footer-items"><a href="/privacy-policy.html">Privacy Policy</a></span> -->
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
/* exported gapiLoaded */
|
||||||
|
/* exported gisLoaded */
|
||||||
|
/* exported handleAuthClick */
|
||||||
|
/* exported handleSignoutClick */
|
||||||
|
|
||||||
|
// TODO(developer): Set to client ID and API key from the Developer Console
|
||||||
|
const CLIENT_ID = '<YOUR_CLIENT_ID>';
|
||||||
|
const API_KEY = '<YOUR_API_KEY>';
|
||||||
|
|
||||||
|
// Discovery doc URL for APIs used by the quickstart
|
||||||
|
const DISCOVERY_DOC = 'https://sheets.googleapis.com/$discovery/rest?version=v4';
|
||||||
|
|
||||||
|
// Authorization scopes required by the API; multiple scopes can be
|
||||||
|
// included, separated by spaces.
|
||||||
|
const SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly';
|
||||||
|
|
||||||
|
let tokenClient;
|
||||||
|
let gapiInited = false;
|
||||||
|
let gisInited = false;
|
||||||
|
|
||||||
|
document.getElementById('authorize_button').style.visibility = 'hidden';
|
||||||
|
document.getElementById('signout_button').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after api.js is loaded.
|
||||||
|
*/
|
||||||
|
function gapiLoaded() {
|
||||||
|
gapi.load('client', intializeGapiClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after the API client is loaded. Loads the
|
||||||
|
* discovery doc to initialize the API.
|
||||||
|
*/
|
||||||
|
async function intializeGapiClient() {
|
||||||
|
await gapi.client.init({
|
||||||
|
apiKey: API_KEY,
|
||||||
|
discoveryDocs: [DISCOVERY_DOC],
|
||||||
|
});
|
||||||
|
gapiInited = true;
|
||||||
|
maybeEnableButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after Google Identity Services are loaded.
|
||||||
|
*/
|
||||||
|
function gisLoaded() {
|
||||||
|
tokenClient = google.accounts.oauth2.initTokenClient({
|
||||||
|
client_id: CLIENT_ID,
|
||||||
|
scope: SCOPES,
|
||||||
|
callback: '', // defined later
|
||||||
|
});
|
||||||
|
gisInited = true;
|
||||||
|
maybeEnableButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables user interaction after all libraries are loaded.
|
||||||
|
*/
|
||||||
|
function maybeEnableButtons() {
|
||||||
|
if (gapiInited && gisInited) {
|
||||||
|
document.getElementById('authorize_button').style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign in the user upon button click.
|
||||||
|
*/
|
||||||
|
function handleAuthClick() {
|
||||||
|
tokenClient.callback = async (resp) => {
|
||||||
|
if (resp.error !== undefined) {
|
||||||
|
throw (resp);
|
||||||
|
}
|
||||||
|
document.getElementById('signout_button').style.visibility = 'visible';
|
||||||
|
document.getElementById('authorize_button').innerText = 'Refresh';
|
||||||
|
await listMajors();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gapi.client.getToken() === null) {
|
||||||
|
// Prompt the user to select a Google Account and ask for consent to share their data
|
||||||
|
// when establishing a new session.
|
||||||
|
tokenClient.requestAccessToken({prompt: 'consent'});
|
||||||
|
} else {
|
||||||
|
// Skip display of account chooser and consent dialog for an existing session.
|
||||||
|
tokenClient.requestAccessToken({prompt: ''});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign out the user upon button click.
|
||||||
|
*/
|
||||||
|
function handleSignoutClick() {
|
||||||
|
const token = gapi.client.getToken();
|
||||||
|
if (token !== null) {
|
||||||
|
google.accounts.oauth2.revoke(token.access_token);
|
||||||
|
gapi.client.setToken('');
|
||||||
|
document.getElementById('content').innerText = '';
|
||||||
|
document.getElementById('authorize_button').innerText = 'Authorize';
|
||||||
|
document.getElementById('signout_button').style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the names and majors of students in a sample spreadsheet:
|
||||||
|
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
|
||||||
|
*/
|
||||||
|
async function listMajors() {
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
// Fetch first 10 files
|
||||||
|
response = await gapi.client.sheets.spreadsheets.values.get({
|
||||||
|
spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
|
||||||
|
range: 'Class Data!A2:E',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
document.getElementById('content').innerText = err.message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const range = response.result;
|
||||||
|
if (!range || !range.values || range.values.length == 0) {
|
||||||
|
document.getElementById('content').innerText = 'No values found.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Flatten to string to display
|
||||||
|
const output = range.values.reduce(
|
||||||
|
(str, row) => `${str}${row[0]}, ${row[4]}\n`,
|
||||||
|
'Name, Major:\n');
|
||||||
|
document.getElementById('content').innerText = output;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
|
||||||
|
<script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user