From 997eed7fd95ee12779a2976e0444218e27f0c00d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:23:22 +0000 Subject: [PATCH 1/3] Initial plan From 7cfd796c20f1008ecf3fe659d75a0498f3d0ea6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:33:41 +0000 Subject: [PATCH 2/3] feat: Add centralized API configuration with localhost fallback Co-authored-by: pmca31 <6774003+pmca31@users.noreply.github.com> --- octofit-tracker/frontend/package-lock.json | 24 +++++++++++++ .../frontend/src/components/Activities.js | 3 +- .../frontend/src/components/Leaderboard.js | 3 +- .../frontend/src/components/Teams.js | 3 +- .../frontend/src/components/Users.js | 7 ++-- .../frontend/src/components/Workouts.js | 3 +- octofit-tracker/frontend/src/config/api.js | 36 +++++++++++++++++++ 7 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 octofit-tracker/frontend/src/config/api.js diff --git a/octofit-tracker/frontend/package-lock.json b/octofit-tracker/frontend/package-lock.json index 5671bf5..5f06c7a 100644 --- a/octofit-tracker/frontend/package-lock.json +++ b/octofit-tracker/frontend/package-lock.json @@ -66,6 +66,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -715,6 +716,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.28.6.tgz", "integrity": "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -1598,6 +1600,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-module-imports": "^7.28.6", @@ -3360,6 +3363,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -3846,6 +3850,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -3899,6 +3904,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -4268,6 +4274,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4366,6 +4373,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5294,6 +5302,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7127,6 +7136,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9864,6 +9874,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -10761,6 +10772,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -12098,6 +12110,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -13232,6 +13245,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -13591,6 +13605,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -13722,6 +13737,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -13746,6 +13762,7 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -14224,6 +14241,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -14466,6 +14484,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -15831,6 +15850,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -15999,6 +16019,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -16428,6 +16449,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.1.tgz", "integrity": "sha512-Gdj3X74CLJJ8zy4URmK42W7wTZUJrqL+z8nyGEr4dTN0kb3nVs+ZvjbTOqRYPD7qX4tUmwyHL9Q9K6T1seW6Yw==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -16499,6 +16521,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -16912,6 +16935,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/octofit-tracker/frontend/src/components/Activities.js b/octofit-tracker/frontend/src/components/Activities.js index 172fb62..bf03eaa 100644 --- a/octofit-tracker/frontend/src/components/Activities.js +++ b/octofit-tracker/frontend/src/components/Activities.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { getApiUrl } from '../config/api'; const Activities = () => { const [activities, setActivities] = useState([]); @@ -7,7 +8,7 @@ const Activities = () => { useEffect(() => { const fetchActivities = async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/activities/`; + const apiUrl = getApiUrl('/api/activities/'); console.log('Fetching from Activities API endpoint:', apiUrl); try { diff --git a/octofit-tracker/frontend/src/components/Leaderboard.js b/octofit-tracker/frontend/src/components/Leaderboard.js index eef4ec3..8197cf2 100644 --- a/octofit-tracker/frontend/src/components/Leaderboard.js +++ b/octofit-tracker/frontend/src/components/Leaderboard.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { getApiUrl } from '../config/api'; const Leaderboard = () => { const [leaderboard, setLeaderboard] = useState([]); @@ -7,7 +8,7 @@ const Leaderboard = () => { useEffect(() => { const fetchLeaderboard = async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/leaderboard/`; + const apiUrl = getApiUrl('/api/leaderboard/'); console.log('Fetching from Leaderboard API endpoint:', apiUrl); try { diff --git a/octofit-tracker/frontend/src/components/Teams.js b/octofit-tracker/frontend/src/components/Teams.js index 73cd37a..6ae6ebe 100644 --- a/octofit-tracker/frontend/src/components/Teams.js +++ b/octofit-tracker/frontend/src/components/Teams.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { getApiUrl } from '../config/api'; const Teams = () => { const [teams, setTeams] = useState([]); @@ -7,7 +8,7 @@ const Teams = () => { useEffect(() => { const fetchTeams = async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/teams/`; + const apiUrl = getApiUrl('/api/teams/'); console.log('Fetching from Teams API endpoint:', apiUrl); try { diff --git a/octofit-tracker/frontend/src/components/Users.js b/octofit-tracker/frontend/src/components/Users.js index e7bf009..a6f5ab6 100644 --- a/octofit-tracker/frontend/src/components/Users.js +++ b/octofit-tracker/frontend/src/components/Users.js @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback } from 'react'; +import { getApiUrl } from '../config/api'; const Users = () => { const [users, setUsers] = useState([]); @@ -10,7 +11,7 @@ const Users = () => { const [saveMessage, setSaveMessage] = useState(''); const fetchUsers = useCallback(async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/users/`; + const apiUrl = getApiUrl('/api/users/'); console.log('Fetching from Users API endpoint:', apiUrl); try { @@ -33,7 +34,7 @@ const Users = () => { }, []); const fetchTeams = useCallback(async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/teams/`; + const apiUrl = getApiUrl('/api/teams/'); console.log('Fetching teams for dropdown:', apiUrl); try { @@ -81,7 +82,7 @@ const Users = () => { const handleSave = async () => { if (!editingUser) return; - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/users/${editingUser.id}/`; + const apiUrl = getApiUrl(`/api/users/${editingUser.id}/`); console.log('Updating user:', apiUrl, formData); try { diff --git a/octofit-tracker/frontend/src/components/Workouts.js b/octofit-tracker/frontend/src/components/Workouts.js index 18c2a5e..eb9647c 100644 --- a/octofit-tracker/frontend/src/components/Workouts.js +++ b/octofit-tracker/frontend/src/components/Workouts.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { getApiUrl } from '../config/api'; const Workouts = () => { const [workouts, setWorkouts] = useState([]); @@ -7,7 +8,7 @@ const Workouts = () => { useEffect(() => { const fetchWorkouts = async () => { - const apiUrl = `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev/api/workouts/`; + const apiUrl = getApiUrl('/api/workouts/'); console.log('Fetching from Workouts API endpoint:', apiUrl); try { diff --git a/octofit-tracker/frontend/src/config/api.js b/octofit-tracker/frontend/src/config/api.js new file mode 100644 index 0000000..9b5db22 --- /dev/null +++ b/octofit-tracker/frontend/src/config/api.js @@ -0,0 +1,36 @@ +/** + * API Configuration + * + * Provides a centralized API base URL configuration with environment-aware fallbacks. + * + * Priority: + * 1. REACT_APP_API_BASE_URL - explicit API base URL override + * 2. REACT_APP_CODESPACE_NAME - GitHub Codespaces environment + * 3. http://localhost:8000 - local development fallback + */ + +const getApiBaseUrl = () => { + // Check for explicit API base URL + if (process.env.REACT_APP_API_BASE_URL) { + return process.env.REACT_APP_API_BASE_URL; + } + + // Check for GitHub Codespaces environment + if (process.env.REACT_APP_CODESPACE_NAME) { + return `https://${process.env.REACT_APP_CODESPACE_NAME}-8000.app.github.dev`; + } + + // Default to localhost for local development + return 'http://localhost:8000'; +}; + +export const API_BASE_URL = getApiBaseUrl(); + +// Helper function to build API endpoint URLs +export const getApiUrl = (endpoint) => { + // Ensure endpoint starts with / + const cleanEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`; + return `${API_BASE_URL}${cleanEndpoint}`; +}; + +export default { API_BASE_URL, getApiUrl }; From 6458d8862c5adedaf0d5b83759944dce3c0596c1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:35:09 +0000 Subject: [PATCH 3/3] docs: Add clarifying comment about API_BASE_URL module load behavior Co-authored-by: pmca31 <6774003+pmca31@users.noreply.github.com> --- octofit-tracker/frontend/src/config/api.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/octofit-tracker/frontend/src/config/api.js b/octofit-tracker/frontend/src/config/api.js index 9b5db22..4dd5608 100644 --- a/octofit-tracker/frontend/src/config/api.js +++ b/octofit-tracker/frontend/src/config/api.js @@ -24,6 +24,10 @@ const getApiBaseUrl = () => { return 'http://localhost:8000'; }; +// Note: API_BASE_URL is computed at module load time based on environment variables. +// In normal React applications, environment variables are set at build time and don't +// change during runtime, so this is the expected behavior. If you need to reconfigure +// the API URL at runtime (e.g., in tests), you'll need to reload the module. export const API_BASE_URL = getApiBaseUrl(); // Helper function to build API endpoint URLs