mirror of
https://github.com/farcasclaudiu/learn-build-apps-copilot-agent.git
synced 2026-06-22 07:01:37 +03:00
feat: refactor API base URL handling and update frontend components for improved data structure
This commit is contained in:
@@ -3,10 +3,10 @@
|
|||||||
# Copy this file to .env.local and fill in your values.
|
# Copy this file to .env.local and fill in your values.
|
||||||
# .env.local is gitignored and never committed.
|
# .env.local is gitignored and never committed.
|
||||||
#
|
#
|
||||||
# VITE_CODESPACE_NAME is required when running inside a GitHub Codespace.
|
# VITE_CODESPACE_NAME can be used to explicitly point at the backend API.
|
||||||
# It is used to build the backend API base URL:
|
# When running inside a GitHub Codespace, the frontend will also auto-detect
|
||||||
# https://${VITE_CODESPACE_NAME}-8000.app.github.dev/api
|
# the backend host from the current app.github.dev URL.
|
||||||
#
|
#
|
||||||
# If unset, the frontend falls back to http://localhost:8000/api.
|
# If unset outside Codespaces, the frontend falls back to http://localhost:8000/api.
|
||||||
|
|
||||||
VITE_CODESPACE_NAME=your-codespace-name-here
|
VITE_CODESPACE_NAME=your-codespace-name-here
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { API_BASE } from '../lib/apiBase'
|
||||||
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
|
||||||
const API_BASE = codespaceName
|
|
||||||
? `https://${codespaceName}-8000.app.github.dev/api`
|
|
||||||
: 'http://localhost:8000/api'
|
|
||||||
|
|
||||||
function Activities() {
|
function Activities() {
|
||||||
const [activities, setActivities] = useState([])
|
const [activities, setActivities] = useState([])
|
||||||
@@ -17,7 +13,7 @@ function Activities() {
|
|||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setActivities(Array.isArray(data) ? data : (data.results ?? []))
|
setActivities(Array.isArray(data) ? data : (data.items ?? data.results ?? []))
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -36,18 +32,22 @@ function Activities() {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
|
<th>Team</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Duration (min)</th>
|
<th>Duration (min)</th>
|
||||||
<th>Date</th>
|
<th>Calories</th>
|
||||||
|
<th>Completed</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{activities.map((activity) => (
|
{activities.map((activity) => (
|
||||||
<tr key={activity._id ?? activity.id}>
|
<tr key={activity._id ?? activity.id}>
|
||||||
<td>{activity.user}</td>
|
<td>{activity.user?.username ?? activity.user}</td>
|
||||||
<td>{activity.activity_type}</td>
|
<td>{activity.team?.name ?? activity.team}</td>
|
||||||
<td>{activity.duration}</td>
|
<td>{activity.type}</td>
|
||||||
<td>{activity.date}</td>
|
<td>{activity.durationMinutes}</td>
|
||||||
|
<td>{activity.caloriesBurned}</td>
|
||||||
|
<td>{activity.completedAt ? new Date(activity.completedAt).toLocaleString() : ''}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { API_BASE } from '../lib/apiBase'
|
||||||
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
|
||||||
const API_BASE = codespaceName
|
|
||||||
? `https://${codespaceName}-8000.app.github.dev/api`
|
|
||||||
: 'http://localhost:8000/api'
|
|
||||||
|
|
||||||
function Leaderboard() {
|
function Leaderboard() {
|
||||||
const [entries, setEntries] = useState([])
|
const [leaderboards, setLeaderboards] = useState([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
|
|
||||||
@@ -17,7 +13,7 @@ function Leaderboard() {
|
|||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setEntries(Array.isArray(data) ? data : (data.results ?? []))
|
setLeaderboards(Array.isArray(data) ? data : (data.items ?? data.results ?? []))
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -35,22 +31,26 @@ function Leaderboard() {
|
|||||||
<table className="table table-striped">
|
<table className="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>Period</th>
|
||||||
<th>Rank</th>
|
<th>Rank</th>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
<th>Score</th>
|
<th>Score</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{entries.map((entry, index) => (
|
{leaderboards.flatMap((leaderboard) =>
|
||||||
<tr key={entry._id ?? entry.id}>
|
leaderboard.entries.map((entry) => (
|
||||||
<td>{index + 1}</td>
|
<tr key={`${leaderboard._id ?? leaderboard.id}-${entry.rank}-${entry.user?._id ?? entry.user?.id ?? entry.user}`}>
|
||||||
<td>{entry.user}</td>
|
<td>{leaderboard.period}</td>
|
||||||
<td>{entry.score}</td>
|
<td>{entry.rank}</td>
|
||||||
</tr>
|
<td>{entry.user?.username ?? entry.user}</td>
|
||||||
))}
|
<td>{entry.points}</td>
|
||||||
|
</tr>
|
||||||
|
)),
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{entries.length === 0 && <p>No leaderboard entries found.</p>}
|
{leaderboards.length === 0 && <p>No leaderboard entries found.</p>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { API_BASE } from '../lib/apiBase'
|
||||||
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
|
||||||
const API_BASE = codespaceName
|
|
||||||
? `https://${codespaceName}-8000.app.github.dev/api`
|
|
||||||
: 'http://localhost:8000/api'
|
|
||||||
|
|
||||||
function Teams() {
|
function Teams() {
|
||||||
const [teams, setTeams] = useState([])
|
const [teams, setTeams] = useState([])
|
||||||
@@ -17,7 +13,7 @@ function Teams() {
|
|||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setTeams(Array.isArray(data) ? data : (data.results ?? []))
|
setTeams(Array.isArray(data) ? data : (data.items ?? data.results ?? []))
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -36,6 +32,7 @@ function Teams() {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Captain</th>
|
||||||
<th>Members</th>
|
<th>Members</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -43,7 +40,12 @@ function Teams() {
|
|||||||
{teams.map((team) => (
|
{teams.map((team) => (
|
||||||
<tr key={team._id ?? team.id}>
|
<tr key={team._id ?? team.id}>
|
||||||
<td>{team.name}</td>
|
<td>{team.name}</td>
|
||||||
<td>{Array.isArray(team.members) ? team.members.join(', ') : team.members}</td>
|
<td>{team.captain?.username ?? team.captain}</td>
|
||||||
|
<td>
|
||||||
|
{Array.isArray(team.members)
|
||||||
|
? team.members.map((member) => member?.username ?? member).join(', ')
|
||||||
|
: team.members}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { API_BASE } from '../lib/apiBase'
|
||||||
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
|
||||||
const API_BASE = codespaceName
|
|
||||||
? `https://${codespaceName}-8000.app.github.dev/api`
|
|
||||||
: 'http://localhost:8000/api'
|
|
||||||
|
|
||||||
function Users() {
|
function Users() {
|
||||||
const [users, setUsers] = useState([])
|
const [users, setUsers] = useState([])
|
||||||
@@ -17,7 +13,7 @@ function Users() {
|
|||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setUsers(Array.isArray(data) ? data : (data.results ?? []))
|
setUsers(Array.isArray(data) ? data : (data.items ?? data.results ?? []))
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { API_BASE } from '../lib/apiBase'
|
||||||
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
|
||||||
const API_BASE = codespaceName
|
|
||||||
? `https://${codespaceName}-8000.app.github.dev/api`
|
|
||||||
: 'http://localhost:8000/api'
|
|
||||||
|
|
||||||
function Workouts() {
|
function Workouts() {
|
||||||
const [workouts, setWorkouts] = useState([])
|
const [workouts, setWorkouts] = useState([])
|
||||||
@@ -17,7 +13,7 @@ function Workouts() {
|
|||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setWorkouts(Array.isArray(data) ? data : (data.results ?? []))
|
setWorkouts(Array.isArray(data) ? data : (data.items ?? data.results ?? []))
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -35,15 +31,19 @@ function Workouts() {
|
|||||||
<table className="table table-striped">
|
<table className="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Title</th>
|
||||||
<th>Description</th>
|
<th>Category</th>
|
||||||
|
<th>Difficulty</th>
|
||||||
|
<th>Duration (min)</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{workouts.map((workout) => (
|
{workouts.map((workout) => (
|
||||||
<tr key={workout._id ?? workout.id}>
|
<tr key={workout._id ?? workout.id}>
|
||||||
<td>{workout.name}</td>
|
<td>{workout.title}</td>
|
||||||
<td>{workout.description}</td>
|
<td>{workout.category}</td>
|
||||||
|
<td>{workout.difficulty}</td>
|
||||||
|
<td>{workout.durationMinutes}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const codespaceName = import.meta.env.VITE_CODESPACE_NAME
|
||||||
|
const browserHost = typeof window !== 'undefined' ? window.location.hostname : ''
|
||||||
|
const isDevelopment = import.meta.env.DEV
|
||||||
|
|
||||||
|
const derivedCodespaceHost = browserHost.endsWith('.app.github.dev')
|
||||||
|
? browserHost.replace(/-\d+\.app\.github\.dev$/, '-8000.app.github.dev')
|
||||||
|
: ''
|
||||||
|
|
||||||
|
export const API_BASE = isDevelopment
|
||||||
|
? '/api'
|
||||||
|
: codespaceName
|
||||||
|
? `https://${codespaceName}-8000.app.github.dev/api`
|
||||||
|
: derivedCodespaceHost
|
||||||
|
? `https://${derivedCodespaceHost}/api`
|
||||||
|
: 'http://localhost:8000/api'
|
||||||
@@ -5,6 +5,12 @@ import react from '@vitejs/plugin-react'
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://127.0.0.1:8000',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
port: 5173,
|
port: 5173,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user