diff --git a/program-finder/backend/src/app.ts b/program-finder/backend/src/app.ts index 856255bc..7c00b69e 100644 --- a/program-finder/backend/src/app.ts +++ b/program-finder/backend/src/app.ts @@ -7,7 +7,10 @@ const app = express(); // Configure CORS app.use(cors({ - origin: 'http://localhost:3000', + origin: [ + 'http://localhost:3000', + 'https://25q1-team3-sand.vercel.app' + ], credentials: true })); diff --git a/program-finder/backend/src/routes/auth.ts b/program-finder/backend/src/routes/auth.ts index d0d8cc4a..86320f35 100644 --- a/program-finder/backend/src/routes/auth.ts +++ b/program-finder/backend/src/routes/auth.ts @@ -52,10 +52,10 @@ router.get('/google/callback', async (req, res) => { ); // Redirect to frontend with token - res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/login?token=${token}`); + res.redirect(`${process.env.NEXT_PUBLIC_FRONTEND_URL || 'http://localhost:3000'}/login?token=${token}`); } catch (error) { console.error('Google OAuth error:', error); - res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/login?error=auth_failed`); + res.redirect(`${process.env.NEXT_PUBLIC_FRONTEND_URL || 'http://localhost:3000'}/login?error=auth_failed`); } }); diff --git a/program-finder/backend/src/server.ts b/program-finder/backend/src/server.ts index 0ef123ea..8e9f945e 100644 --- a/program-finder/backend/src/server.ts +++ b/program-finder/backend/src/server.ts @@ -1,7 +1,32 @@ import app from './app'; import { initializeDb } from './db'; -const PORT = process.env.PORT || 3001; +const app = express(); + +app.use(cors({ + origin: process.env.NEXT_PUBLIC_FRONTEND_URL || 'http://localhost:3000', + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +})); + +app.use(express.json()); + +// Add a simple test endpoint +app.get('/api/health', (req, res) => { + res.json({ status: 'ok', message: 'Backend server is running' }); +}); + +// Auth routes +app.use('/api/auth', authRoutes); + +// Program routes +app.use('/api', programRoutes); + +// Bookmark routes +app.use('/api/bookmarks', bookmarkRoutes); + +const PORT = 3001; // Initialize the database before starting the server app.listen(PORT, () => { diff --git a/program-finder/frontend/api/index.js b/program-finder/frontend/api/index.js index 674d83c5..eba0ebb9 100644 --- a/program-finder/frontend/api/index.js +++ b/program-finder/frontend/api/index.js @@ -9,7 +9,7 @@ app.use(cors()); // Proxy middleware configuration const apiProxy = createProxyMiddleware({ - target: process.env.BACKEND_URL || 'http://localhost:3001', + target: process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001', changeOrigin: true, pathRewrite: { '^/api': '', // Remove /api prefix when forwarding to backend diff --git a/program-finder/frontend/src/app/api/bookmarks/[...path]/route.ts b/program-finder/frontend/src/app/api/bookmarks/[...path]/route.ts index 18842df7..3905c2cd 100644 --- a/program-finder/frontend/src/app/api/bookmarks/[...path]/route.ts +++ b/program-finder/frontend/src/app/api/bookmarks/[...path]/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; -const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3001'; +const BACKEND_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001'; export async function GET( request: NextRequest, diff --git a/program-finder/frontend/src/app/programs/ProgramsContent.tsx b/program-finder/frontend/src/app/programs/ProgramsContent.tsx index 70f9d10b..3d0c111f 100644 --- a/program-finder/frontend/src/app/programs/ProgramsContent.tsx +++ b/program-finder/frontend/src/app/programs/ProgramsContent.tsx @@ -6,6 +6,7 @@ import { ProgramData } from '../../interfaces/ProgramData'; import { ProgramCard } from '../../components/ProgramCard'; import { SearchBar } from '../../components/SearchBar'; import PageLayout from '../../components/PageLayout'; +import config from '@/config'; interface SearchFilters { ageGroup: string; @@ -31,45 +32,51 @@ export default function ProgramsContent() { useEffect(() => { fetchPrograms(); - }, [initialCategory]); + }, [searchParams]); - const fetchPrograms = async (zip = '', searchFilters: SearchFilters = filters) => { + const fetchPrograms = async () => { setLoading(true); setError(null); - setCurrentPage(1); // Reset to first page when searching try { const queryParams = new URLSearchParams(); + const zip = searchParams?.get('zip'); + const keyword = searchParams?.get('keyword'); + const distance = searchParams?.get('distance'); + if (zip) queryParams.append('zip', zip); - if (searchFilters.ageGroup) queryParams.append('ageGroup', searchFilters.ageGroup); - if (searchFilters.category) queryParams.append('category', searchFilters.category); - if (searchFilters.distance) queryParams.append('distance', searchFilters.distance); + if (keyword) queryParams.append('keyword', keyword); + if (distance) queryParams.append('distance', distance); - const apiUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:3001'; - const url = apiUrl + `/api/programs${queryParams.toString() ? `?${queryParams}` : ''}`; + const url = `${config.apiBaseUrl}/programs${queryParams.toString() ? `?${queryParams}` : ''}`; console.log('Fetching programs from:', url); const res = await fetch(url); if (!res.ok) { - throw new Error(`Failed to fetch programs: ${res.statusText}`); + throw new Error('Failed to fetch programs'); } - const data = await res.json(); - if (!Array.isArray(data)) { - throw new Error('Invalid response format'); - } - console.log(`Fetched ${data.length} programs from the API`); setPrograms(data); - } catch (err) { - console.error('Fetch error:', err); - setError(err instanceof Error ? err.message : 'Unable to fetch programs. Please try again later.'); - setPrograms([]); + } catch (error) { + console.error('Error fetching programs:', error); + setError('Failed to load programs. Please try again later.'); } finally { setLoading(false); } }; const search = (zip: string, searchFilters: SearchFilters) => { - fetchPrograms(zip, searchFilters); + setFilters(searchFilters); + // Update URL with new search parameters + const params = new URLSearchParams(); + if (zip) params.set('zip', zip); + if (searchFilters.category) params.set('category', searchFilters.category); + if (searchFilters.distance) params.set('distance', searchFilters.distance); + + // Update URL without page reload + window.history.pushState({}, '', `?${params.toString()}`); + + // Fetch programs with new parameters + fetchPrograms(); }; // Get current programs for pagination @@ -93,7 +100,7 @@ export default function ProgramsContent() {

Search Programs

- +
{loading && ( diff --git a/program-finder/frontend/src/config/index.ts b/program-finder/frontend/src/config/index.ts index 5d297b43..97a0efbb 100644 --- a/program-finder/frontend/src/config/index.ts +++ b/program-finder/frontend/src/config/index.ts @@ -15,7 +15,7 @@ const devConfig: Config = { const prodConfig: Config = { // These will be replaced in production by environment variables googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || 'AIzaSyBfMtxd8CK-Zi_noMDZ3nFaxf6BTVo_hWc', - apiBaseUrl: process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001/api', + apiBaseUrl: `${process.env.NEXT_PUBLIC_API_BASE_URL}/api` || 'https://program-finder.fly.dev/api', }; // Use production config when NODE_ENV is 'production', otherwise use development config diff --git a/program-finder/test-connection.js b/program-finder/test-connection.js index 0c42675d..7dd70777 100644 --- a/program-finder/test-connection.js +++ b/program-finder/test-connection.js @@ -3,7 +3,7 @@ async function testBackendConnection() { try { console.log('Testing connection to backend server...'); - const response = await fetch('http://localhost:3001/api/health'); + const response = await fetch((process.env.NEXT_PUBLIC_API_BASE_URL + '/api/health') || 'http://localhost:3001/api/health'); if (!response.ok) { throw new Error(`Failed with status: ${response.status}`); @@ -22,7 +22,7 @@ async function testBackendConnection() { async function testBookmarksEndpoint() { try { console.log('\nTesting connection to bookmarks endpoint...'); - const response = await fetch('http://localhost:3001/api/bookmarks', { + const response = await fetch((process.env.NEXT_PUBLIC_FRONTEND_URL + '/api/bookmarks') || 'http://localhost:3001/api/bookmarks', { headers: { 'Authorization': 'Bearer test-token' } diff --git a/program-finder/test-nextjs-api.js b/program-finder/test-nextjs-api.js index 5024cecc..94634c16 100644 --- a/program-finder/test-nextjs-api.js +++ b/program-finder/test-nextjs-api.js @@ -3,7 +3,7 @@ async function testNextJsBookmarksApi() { try { console.log('Testing connection to Next.js bookmarks API...'); - const response = await fetch('http://localhost:3000/api/bookmarks', { + const response = await fetch((process.env.NEXT_PUBLIC_FRONTEND_URL + '/api/bookmarks') || 'http://localhost:3000/api/bookmarks', { headers: { 'Authorization': 'Bearer test-token' }