From e27bf7b7c8cbc9e24eae417a8fd27f75b28fc9a1 Mon Sep 17 00:00:00 2001 From: John Scolaro Date: Fri, 20 Oct 2023 15:19:09 +1000 Subject: [PATCH] Handle missing cookies issue (#30) There is an issue somewhere that results in users requesting data from this website without session cookies. I could reproduce on my phone by logging in, hard-closing the browser, and then re-opening it. On re-open the browser attempts to load the 'logged in' screen with no cookies. This PR does the following: 1: Delete a whole lot of random stuff from the backend. We don't need any of the html, css, and javascript any more since next.js handles everything now. 2: Wraps all fetch requests so that if a 401 Unauthorized is received, then the user gets re-routed to home. 3: The backend routes now have a decorator to check for the session cookie instead of doing it in each route individually, and instead of manually rerouting to 'index' which doesn't exist, they just return 401 status codes. --- backend/active_statistics/gui/plot_tabs.py | 15 +- backend/active_statistics/gui/table_tab.py | 15 +- backend/active_statistics/server.py | 57 +- .../static/buttons_script.js | 44 -- .../active_statistics/static/home_script.js | 173 ------ .../api_logo_pwrdBy_strava_stack_gray.svg | 1 - .../images/btn_strava_connectwith_orange.svg | 14 - .../static/images/github-mark-white.svg | 1 - .../active_statistics/static/images/icon.png | Bin 612 -> 0 bytes .../active_statistics/static/index_script.js | 66 --- .../static/loading_styles.css | 66 --- .../static/plot_tab_script.js | 39 -- backend/active_statistics/static/styles.css | 536 ------------------ .../static/table_tab_script.js | 71 --- .../download_data_main_content_container.html | 44 -- backend/active_statistics/templates/home.html | 64 --- .../active_statistics/templates/index.html | 88 --- .../plot_tab_main_content_container.html | 18 - .../table_tab_main_content_container.html | 18 - backend/active_statistics/utils/routes.py | 16 + frontend/app/home/[key]/page.tsx | 17 +- .../app/home/download_strava_data/page.tsx | 20 +- frontend/app/home/layout.tsx | 109 +++- frontend/components/base.tsx | 13 +- frontend/components/plot_container.tsx | 17 +- frontend/components/side_bar/side_bar.tsx | 14 +- frontend/components/strava_login_button.tsx | 16 +- frontend/lib/fetch.ts | 32 ++ 28 files changed, 224 insertions(+), 1360 deletions(-) delete mode 100644 backend/active_statistics/static/buttons_script.js delete mode 100644 backend/active_statistics/static/home_script.js delete mode 100644 backend/active_statistics/static/images/api_logo_pwrdBy_strava_stack_gray.svg delete mode 100644 backend/active_statistics/static/images/btn_strava_connectwith_orange.svg delete mode 100644 backend/active_statistics/static/images/github-mark-white.svg delete mode 100644 backend/active_statistics/static/images/icon.png delete mode 100644 backend/active_statistics/static/index_script.js delete mode 100644 backend/active_statistics/static/loading_styles.css delete mode 100644 backend/active_statistics/static/plot_tab_script.js delete mode 100644 backend/active_statistics/static/styles.css delete mode 100644 backend/active_statistics/static/table_tab_script.js delete mode 100644 backend/active_statistics/templates/download_data_main_content_container.html delete mode 100644 backend/active_statistics/templates/home.html delete mode 100644 backend/active_statistics/templates/index.html delete mode 100644 backend/active_statistics/templates/plot_tab_main_content_container.html delete mode 100644 backend/active_statistics/templates/table_tab_main_content_container.html create mode 100644 backend/active_statistics/utils/routes.py create mode 100644 frontend/lib/fetch.ts diff --git a/backend/active_statistics/gui/plot_tabs.py b/backend/active_statistics/gui/plot_tabs.py index 969f872..58fac2c 100644 --- a/backend/active_statistics/gui/plot_tabs.py +++ b/backend/active_statistics/gui/plot_tabs.py @@ -9,16 +9,9 @@ get_activity_iterator, get_summary_activity_iterator, ) +from active_statistics.utils.routes import unauthorized_if_no_session_cookie from active_statistics.utils.s3 import get_visualisation_data -from flask import ( - Flask, - jsonify, - make_response, - redirect, - render_template, - session, - url_for, -) +from flask import Flask, jsonify, make_response, redirect, session, url_for from stravalib.model import Activity from werkzeug.wrappers import Response @@ -46,10 +39,8 @@ def generate_and_register_routes( self, app: Flask, evm: EnvironmentVariableManager ) -> None: def get_plot_function(tab: PlotTab): + @unauthorized_if_no_session_cookie def plot_function() -> Response: - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) if evm.use_s3(): diff --git a/backend/active_statistics/gui/table_tab.py b/backend/active_statistics/gui/table_tab.py index 5226ac7..0f6b712 100644 --- a/backend/active_statistics/gui/table_tab.py +++ b/backend/active_statistics/gui/table_tab.py @@ -9,16 +9,9 @@ get_activity_iterator, get_summary_activity_iterator, ) +from active_statistics.utils.routes import unauthorized_if_no_session_cookie from active_statistics.utils.s3 import get_visualisation_data -from flask import ( - Flask, - jsonify, - make_response, - redirect, - render_template, - session, - url_for, -) +from flask import Flask, jsonify, make_response, redirect, session, url_for from stravalib.model import Activity from werkzeug.wrappers import Response @@ -48,10 +41,8 @@ def generate_and_register_routes( self, app: Flask, evm: EnvironmentVariableManager ) -> None: def get_data_function(tab: TableTab): + @unauthorized_if_no_session_cookie def data_function() -> Response: - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) if evm.use_s3(): diff --git a/backend/active_statistics/server.py b/backend/active_statistics/server.py index b408870..af9ef9d 100644 --- a/backend/active_statistics/server.py +++ b/backend/active_statistics/server.py @@ -21,6 +21,7 @@ we_have_detailed_activities_for_athlete, we_have_summary_activities_for_athlete, ) +from active_statistics.utils.routes import unauthorized_if_no_session_cookie from active_statistics.utils.sentry import set_up_sentry_for_server from flask import ( Flask, @@ -49,20 +50,6 @@ app.secret_key = evm.get_flask_secret_key() -def get_strava_auth_url() -> str: - logger.info("getting auth url") - scheme = "https" if evm.is_production() else "http" - redirect_uri = ( - f"{scheme}://{evm.get_domain()}:{str(evm.get_port())}/api/authenticate" - ) - - client = Client() - authorize_url: str = client.authorization_url( - client_id=evm.get_strava_client_id(), redirect_uri=redirect_uri - ) - return authorize_url - - @app.route("/api/example_chart_data") def chart_data() -> Response: current_file_dir_path = os.path.dirname(os.path.realpath(__file__)) @@ -111,14 +98,12 @@ def authenticate() -> Response: @app.route("/api/refresh_summary_data") +@unauthorized_if_no_session_cookie def refresh_summary_data() -> Response: """ When this endpoint is hit, we will endevour to re-download the users summary data, assuming they haven't already refreshed in the last day. """ - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) summary_refresh_min_period = dt.timedelta(days=1) @@ -165,14 +150,12 @@ def refresh_summary_data() -> Response: @app.route("/api/refresh_detailed_data") +@unauthorized_if_no_session_cookie def refresh_detailed_data() -> Response: """ When this endpoint is hit, we will endevour to re-download the users detailed activity data, assuming they haven't already refreshed in the last day. """ - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) # In case anyone decides to be smart and just manually ping this endpoint @@ -228,15 +211,12 @@ def refresh_detailed_data() -> Response: @app.route("/api/summary_data_status") +@unauthorized_if_no_session_cookie def summary_data_status() -> Response: """ An endpoint that is constantly polled by the webserver for the status of the data until it eventually returns that data has been downloaded. """ - - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) # Firstly, if we are running in local mode, just check if there is data locally. @@ -325,15 +305,12 @@ def summary_data_status() -> Response: @app.route("/api/detailed_data_status") +@unauthorized_if_no_session_cookie def detailed_data_status() -> Response: """ An endpoint that is constantly polled by the webserver for the status of the data until it eventually returns that data has been downloaded. """ - - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) # Firstly, if we are running in local mode, just check if there is data locally. @@ -421,24 +398,9 @@ def detailed_data_status() -> Response: # Shouldn't get here. -@app.route("/api/download_data") -def download_data() -> Response: - if "athlete_id" not in session: - return redirect(url_for("index")) - - return make_response( - render_template( - "download_data_main_content_container.html", - explanation="Welcome to Active Statistics! This tab is where you can refresh your plots with your latest data. There are two types of visualisation on this website. Visualisations that require 'detailed data' and visualisations that require summmary data. The summary and visualisation tabs are seperated on the left side with small horizontal lines. Summary data is automatically downloaded when you log in for the first time because it only takes a few seconds to download. If you wish to view visualisation that require detailed data, you'll have to manually click the 'refresh detailed data' button. Be prepared - this can take a while. It may take ~30 minutes if you have over 400 activities.", - ) - ) - - @app.route("/api/logout") +@unauthorized_if_no_session_cookie def logout() -> Response: - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) redis.delete_strava_api_access_tokens(athlete_id) @@ -447,17 +409,15 @@ def logout() -> Response: session.clear() # Redirect to index to reconnect with strava. - return redirect(url_for("index")) + return redirect("/") @app.route("/api/paid") +@unauthorized_if_no_session_cookie def paid() -> Response: """ Responds with whether this user is paid or not. """ - if "athlete_id" not in session: - return redirect(url_for("index")) - athlete_id = int(session["athlete_id"]) # For now, nobody has paid. Unless you're running this locally, then you can have access to it. @@ -481,6 +441,7 @@ def to_dict(self) -> dict[str, Any]: @app.route("/api/tabs") +@unauthorized_if_no_session_cookie def tabs_route() -> Response: def expand_tabs(tabs: list[Tab | TabGroup]) -> list[Any]: json_tabs = [] diff --git a/backend/active_statistics/static/buttons_script.js b/backend/active_statistics/static/buttons_script.js deleted file mode 100644 index fdb33f9..0000000 --- a/backend/active_statistics/static/buttons_script.js +++ /dev/null @@ -1,44 +0,0 @@ -import { startPolling } from "./home_script.js"; - -$(document).ready(function () { - $('.step-container').click(step_container_clicked); -}); - -function step_container_clicked() { - // Check if the clicked element has the "greyed-out" class - if ($(this).hasClass('greyed-out')) { - return; // Exit the function without performing any action - } - - var url = $(this).data('url'); - - // Remove 'clicked' class from all divs - $('.step-container').removeClass('clicked'); - - // Add 'clicked' class to the clicked div - $(this).addClass('clicked'); - - // Call the page endpoint to get the new page and re-render the main content container - $.ajax({ - url: url, - method: 'GET', - success: (response) => { - // Replace the main content container with the response we get. - $('.main-content-container').html(response); - - // In the special case that this is the "Download Strava Data" button, also - // block access to all other buttons and start polling again to unblock them. - if ($(this).attr('id') === 'download-data') { - let summary_polling_function = startPolling(true); - let detailed_polling_function = startPolling(false); - summary_polling_function(); - detailed_polling_function(); - } - }, - error: error_handler - }); -} - -function error_handler(error) { - console.log(error); -} diff --git a/backend/active_statistics/static/home_script.js b/backend/active_statistics/static/home_script.js deleted file mode 100644 index d98eb7e..0000000 --- a/backend/active_statistics/static/home_script.js +++ /dev/null @@ -1,173 +0,0 @@ -// Add an event listener for the DOMContentLoaded event -document.addEventListener("DOMContentLoaded", function () { - let summary_polling_function = startPolling(true); - let detailed_polling_function = startPolling(false); - summary_polling_function(); - detailed_polling_function(); -}); - -export function startPolling(summary) { - make_step_containers_unclickable(summary); - make_refresh_button_unclickable(summary); - - function get_data_status(summary) { - let url = (summary) ? '/summary_data_status' : '/detailed_data_status'; - - fetch(url) - .then(response => response.json()) - .then(data => { - - // If data.message is Null, that means that there is no record of us ever having fetched data for this - // user. If this is the summary refresh request, hit the refresh endpoint and keep polling as long as - // the response to the refresh request isn't an error. - if (data.status === null) { - if (summary) { - let refresh_data_function = get_refresh_data_function( - summary, - (data) => { - // If the refresh message has been accepted, update the log message and continue polling. - add_log_line_to_log(summary, data.message); - setTimeout(get_data_status, 2000, summary) - }, - (data) => { - // If the refresh message is unsuccessful, then stop polling and unlock the refresh button. - add_log_line_to_log(summary, data.message); - make_refresh_button_clickable(summary); - } - ); - refresh_data_function(); - return; - } else { - // Otherwise if it's detailed, just log it, stop polling, and unlock the refresh button. - add_log_line_to_log(summary, data.message); - make_refresh_button_clickable(summary); - } - } else { - - // Otherwise update the content of the log container. - add_log_line_to_log(summary, data.message); - - if (data.stop_polling) { - if (data.status == 'finished') { - make_step_containers_clickable(summary); - } - make_refresh_button_clickable(summary); - } else { - setTimeout(get_data_status, 2000, summary) - } - } - }) - .catch(error => { - console.error('Error polling endpoint:', error); - }); - } - - return function () { - get_data_status(summary); - }; -} - -function make_step_containers_clickable(summary) { - // Select all elements with the class 'step-container' - const stepContainers = document.querySelectorAll('.step-container'); - - // Loop through each element and remove the 'greyed-out' class - stepContainers.forEach((element) => { - // download-data is a special case. We never want to grey/ungray it. - if (element.id !== 'download-data') { - if (element.classList.contains('summary') == summary) { - element.classList.remove('greyed-out'); - } - } - }); -} - -export function make_step_containers_unclickable(summary) { - // Select all elements with the class 'step-container' - const stepContainers = document.querySelectorAll('.step-container'); - - // Loop through each element - stepContainers.forEach((element) => { - // download-data is a special case. We never want to grey/ungray it. - if (element.id !== 'download-data') { - if (element.classList.contains('summary') == summary) { - element.classList.add('greyed-out'); - } - } - }); -} - -export function make_refresh_button_clickable(summary) { - let id = (summary) ? 'summary-refresh-button' : 'detailed-refresh-button'; - let refresh_button = document.getElementById(id); - refresh_button.classList.remove('greyed-out'); -} - - -export function make_refresh_button_unclickable(summary) { - let id = (summary) ? 'summary-refresh-button' : 'detailed-refresh-button'; - let refresh_button = document.getElementById(id); - refresh_button.classList.add('greyed-out'); -} - -export function add_event_to_summary_refresh_button() { - const buttonDiv = document.getElementById('summary-refresh-button'); - let summary = true; - - let button_function = get_refresh_data_function(summary, (data) => { - add_log_line_to_log(summary, data.message); - let poll_function = startPolling(true); - poll_function(); - }, (data) => { - add_log_line_to_log(summary, data.message); - }); - - buttonDiv.addEventListener('click', () => { - // Only call the button function if the button isn't greyed out. - if (!buttonDiv.classList.contains('greyed-out')) { - button_function(); - } - }); -} - -export function add_event_to_detailed_refresh_button() { - const buttonDiv = document.getElementById('detailed-refresh-button'); - let summary = false; - - let button_function = get_refresh_data_function(summary, (data) => { - add_log_line_to_log(summary, data.message); - let poll_function = startPolling(false); - poll_function(); - }, (data) => { - add_log_line_to_log(summary, data.message); - }); - - buttonDiv.addEventListener('click', () => { - // Only call the button function if the button isn't greyed out. - if (!buttonDiv.classList.contains('greyed-out')) { - button_function(); - } - }); -} - -function get_refresh_data_function(summary, f_refresh_success, f_refresh_fail) { - function attempt_refresh_data() { - var url = (summary) ? 'refresh_summary_data' : 'refresh_detailed_data'; - fetch(url).then(response => response.json()) - .then(data => { - if (data.refresh_accepted) { - f_refresh_success(data); - } else { - f_refresh_fail(data); - } - }).catch(error => { - console.error('Error polling endpoint:', error); - }) - } - return attempt_refresh_data -} - -function add_log_line_to_log(summary, message) { - var logContainer = document.getElementById((summary) ? 'summary-log-container-text' : 'detailed-log-container-text'); - logContainer.innerHTML = message; -} diff --git a/backend/active_statistics/static/images/api_logo_pwrdBy_strava_stack_gray.svg b/backend/active_statistics/static/images/api_logo_pwrdBy_strava_stack_gray.svg deleted file mode 100644 index 427cd62..0000000 --- a/backend/active_statistics/static/images/api_logo_pwrdBy_strava_stack_gray.svg +++ /dev/null @@ -1 +0,0 @@ -api_logo diff --git a/backend/active_statistics/static/images/btn_strava_connectwith_orange.svg b/backend/active_statistics/static/images/btn_strava_connectwith_orange.svg deleted file mode 100644 index 21957c9..0000000 --- a/backend/active_statistics/static/images/btn_strava_connectwith_orange.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - btn_strava_connectwith_orange - Created with Sketch. - - - - - - - - - diff --git a/backend/active_statistics/static/images/github-mark-white.svg b/backend/active_statistics/static/images/github-mark-white.svg deleted file mode 100644 index c679c23..0000000 --- a/backend/active_statistics/static/images/github-mark-white.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/active_statistics/static/images/icon.png b/backend/active_statistics/static/images/icon.png deleted file mode 100644 index ccf8124deeb98c2f485a8642acf7555563f9b4c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 zcmV-q0-ODbP)9y3cSDjC*&Zl*+Z`Z#_ zSHRl6_xkq3+`(U>SkUCoxYe|UxPYU{pH!Pnv(vA4uyN<{=3AdrmBEmo$D3)WW6I#j zWu;!(>DO_rYQ){al);bp`}f@I+SKOKy4SXPv2^V8?BMO+a;NkOz##FQ40OnLZ&jzBRj@iJ1?wefT zvu`nhMc;t0UqaW$qr(CcRLe~~Qx?!gwIWyD5f7lNHN1KZU>(hd9?lrRCYr6O*@lV2 zK-qL)`axiTV#h>lff&WEvU{-m0YGj4LE#V8fdqgS@<4|SA*lz9JVY4P0%ODpjgvr% zn3wU$j09lCW5kmh;1sFtTM_}BA)Q}*NmMt@1tLKz_5znQP+kTO;F(`u1~za7f88)u zonQku@VC;`9m+8YB<7B3-J?uN-~sm02C7G40m|kM@PxWY0MFzXNtvV02;c?o)dh-a ykqa0{RF%5R`ws91^G?h!{!~FMI;@`qe_S7f=n)S(w1N}>0000 - {{ explanation }} - -
-
-
-
- Results of the refresh summary data. -
-
-
-
-
- Refresh Summary Data -
-
-
-
-
-
-
- Results of the refresh detailed data. -
-
-
-
-
- Refresh Detailed Data -
-
-
-
-
- - - diff --git a/backend/active_statistics/templates/home.html b/backend/active_statistics/templates/home.html deleted file mode 100644 index e3937b9..0000000 --- a/backend/active_statistics/templates/home.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - -
-
-
- -
-
- Logout -
-
-
-
- -
- {{default_content | safe}} -
-
-
- - - diff --git a/backend/active_statistics/templates/index.html b/backend/active_statistics/templates/index.html deleted file mode 100644 index 9704a51..0000000 --- a/backend/active_statistics/templates/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - Home Page - - - - -
-
- -
-
-
-
- Get interesting statistics about your Strava activities for free! Active Statistics is an open - source data visualisation project. Here is an example plot showing personal bests over time: -
-
-
-
-
-
-
-
-
-
- To view your stats, please connect with Strava: -
- -
-
-

- Frequently asked Questions:

- Who are you?
- I'm John! I wanted to visualise data that Strava stores in more ways than Strava does. I enjoy - data visualisation and make websites for my day job, so this is a fun combination of things I - enjoy. I intend to keep this website operational and free so long as it doesn't become - prohibatively expensive to maintain!

- What do I do with your data?
- When granted permission, I download all your Strava activity data and use it to generate a - number of visualisations. Because I'm really cheap, I delete all your data after a month of not - accessing it to avoid paying money to store data I realistically don't care about. Don't worry, - I'm not using it for anything nefarious.

- I have a cool idea for something to add to your site!
- Neat! That's not a question, but feel free to contribute to - this website here, or if you have - any other questions, email me here.

-

-
-
-
- -
-
-
-
- - - - diff --git a/backend/active_statistics/templates/plot_tab_main_content_container.html b/backend/active_statistics/templates/plot_tab_main_content_container.html deleted file mode 100644 index b9609af..0000000 --- a/backend/active_statistics/templates/plot_tab_main_content_container.html +++ /dev/null @@ -1,18 +0,0 @@ -
- {{ explanation }} -
-
-
-
-
-
-
-
-
- diff --git a/backend/active_statistics/templates/table_tab_main_content_container.html b/backend/active_statistics/templates/table_tab_main_content_container.html deleted file mode 100644 index 546f4c3..0000000 --- a/backend/active_statistics/templates/table_tab_main_content_container.html +++ /dev/null @@ -1,18 +0,0 @@ -
- {{ explanation }} -
-
-
-
-
-
-
-
-
- diff --git a/backend/active_statistics/utils/routes.py b/backend/active_statistics/utils/routes.py new file mode 100644 index 0000000..c08a9e4 --- /dev/null +++ b/backend/active_statistics/utils/routes.py @@ -0,0 +1,16 @@ +from functools import wraps + +from flask import Response, session + + +def unauthorized_if_no_session_cookie(view_func): + @wraps(view_func) + def decorated_view(*args, **kwargs): + # If there is no session cookie, return a 401: Unauthorized response. + if "athlete_id" not in session: + return Response(response="Unauthorized", status=401) + + # If the session cookie is present, proceed with the original view function + return view_func(*args, **kwargs) + + return decorated_view diff --git a/frontend/app/home/[key]/page.tsx b/frontend/app/home/[key]/page.tsx index a7a1103..8392712 100644 --- a/frontend/app/home/[key]/page.tsx +++ b/frontend/app/home/[key]/page.tsx @@ -4,24 +4,29 @@ import { CenteredSpinner } from "@/components/spinner/spinner"; import { useEffect, useState } from "react"; import Plot from "react-plotly.js"; import Table from "./components/table/table"; +import { useRouter } from "next/navigation"; +import { wrappedFetch } from "@/lib/fetch"; export default function Page({ params }: { params: { key: string } }) { const [loaded, setLoaded] = useState(false); const [data, setData] = useState({}); const [error, setError] = useState(false); + const router = useRouter(); useEffect(() => { const url = `/api/data/${params.key}`; - fetch(url) - .then((response) => response.json()) - .then((data) => { + wrappedFetch( + url, + (data) => { setData(data); setLoaded(true); - }) - .catch((err) => { + }, + (err) => { setError(true); setLoaded(true); - }); + }, + router + ); }, [params.key]); if (!loaded) { diff --git a/frontend/app/home/download_strava_data/page.tsx b/frontend/app/home/download_strava_data/page.tsx index d09df7e..2eb44bf 100644 --- a/frontend/app/home/download_strava_data/page.tsx +++ b/frontend/app/home/download_strava_data/page.tsx @@ -3,6 +3,8 @@ import { useContext } from "react"; import { HomeContext } from "../layout"; import { Spinner } from "@/components/spinner/spinner"; +import { useRouter } from "next/navigation"; +import { wrappedFetch } from "@/lib/fetch"; export default function Page() { return ( @@ -59,6 +61,7 @@ function DownloadDataCard({ type }: { type: "summary" | "detailed" }) { const title = type == "detailed" ? "Download Detailed Data" : "Download Summary Data"; const disable_and_blur = type == "detailed" && !homeContext.paidUser.paid; const message = dataStatus.message; + const router = useRouter(); var statusContent: any = ""; if (dataStatus.status == "finished") { @@ -89,7 +92,7 @@ function DownloadDataCard({ type }: { type: "summary" | "detailed" }) { ); - function buttonClickFunction(type: "detailed" | "summary") { + function buttonClickFunction(type: "detailed" | "summary", router: any) { // If the button is clicked, we want to hit the 'refresh_data' endpoint and deal with it's response. // Then we want to set stopPolling to false and let the page start polling the status endpoint again. const url = @@ -99,9 +102,9 @@ function DownloadDataCard({ type }: { type: "summary" | "detailed" }) { ? homeContext.setSummaryDataStatus : homeContext.setDetailedDataStatus; - fetch(url) - .then((response) => response.json()) - .then((data) => { + wrappedFetch( + url, + (data) => { if (data.refresh_accepted) { updateFunction({ message: "Attempting to refresh data.", @@ -115,7 +118,12 @@ function DownloadDataCard({ type }: { type: "summary" | "detailed" }) { stopPolling: true, }); } - }); + }, + () => { + console.log("Error while trying to refresh data."); + }, + router + ); } return ( @@ -133,7 +141,7 @@ function DownloadDataCard({ type }: { type: "summary" | "detailed" }) {