diff --git a/frontend/src/pages/download.tsx b/frontend/src/pages/download.tsx index 1991a35..7ad3b06 100644 --- a/frontend/src/pages/download.tsx +++ b/frontend/src/pages/download.tsx @@ -157,37 +157,39 @@ const DownloadPage: React.FC = () => { {error &&

{error}

} -
-

Available Packages:

- {packages.length > 0 ? ( + {packages.length > 0 ? ( +
+

Available Packages:

- ) : ( -

No packages found. Try a different search term.

- )} - -
- - + +
+ + Current Page: {offset + 1} + +
-
+ ) : ( +

No packages found. Try a different search term.

+ )} + ); }; -export default DownloadPage; +export default DownloadPage; \ No newline at end of file diff --git a/frontend/src/pages/rating.tsx b/frontend/src/pages/rating.tsx index 8efdfb5..b8820e9 100644 --- a/frontend/src/pages/rating.tsx +++ b/frontend/src/pages/rating.tsx @@ -1,44 +1,193 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import PageLayout from './pageLayout'; +interface PackageMetadata { + ID: string; + Name: string; + Version: string; +} + +interface RatingData { + overall: number; + dependencyPinning: number; + codeReviewMetric: number; +} + const RatingPage: React.FC = () => { - const [packageName, setPackageName] = useState(''); - const [ratingData, setRatingData] = useState({ - overall: 4, - dependencyPinning: 0.8, - codeReviewMetric: 0.75, - }); - - const handleSearch = (e: React.FormEvent) => { - e.preventDefault(); - console.log('Searching for:', packageName); - // Add logic to fetch rating details for the entered package name + const [searchTerm, setSearchTerm] = useState(''); + const [packages, setPackages] = useState([]); + const [ratingData, setRatingData] = useState(null); + const [authToken, setAuthToken] = useState(null); + const [error, setError] = useState(null); + const [offset, setOffset] = useState(0); + + // Retrieve auth token from localStorage on component mount + useEffect(() => { + const token = localStorage.getItem('authToken'); + if (token) { + setAuthToken(token); + } else { + alert('Authentication token not found. Please log in.'); + } + }, []); + + // Fetch packages based on search term and offset (pagination) + const handleSearch = async (page = 0) => { + setError(null); + setPackages([]); + setRatingData(null); // Reset rating data on new search + + if (!authToken) { + alert('Authentication token is missing. Please log in.'); + return; + } + + try { + const requestBody = [{ Name: searchTerm }]; + + const response = await fetch(`/packages?offset=${page}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Authorization': authToken, + }, + body: JSON.stringify(requestBody), + }); + + + // Simulate response data + // const response1 = JSON.stringify({ + // status: 200, + // data: [ + // { + // Name: 'example-package', + // Version: '1.0.0', + // ID: '1', + // }, + // { + // Name: 'another-package', + // Version: '2.0.1', + // ID: '2', + // }, + // ], + // headers: { + // offset: '10', + // }, + // }); + // const response = JSON.parse(response1); + + if (response.status === 200) { + const data: PackageMetadata[] = await response.json(); + setPackages(data); + setOffset(page); // Update offset with the current page number + } else if (response.status === 400) { + setError('Search failed: Missing fields or invalid query.'); + } else if (response.status === 403) { + setError('Search failed: Authentication failed due to invalid or missing AuthenticationToken.'); + } else if (response.status === 413) { + setError('Search failed: Too many packages returned.'); + } else { + setError('Search failed with an unknown error.'); + } + } catch (err) { + console.error('Error during search:', err); + setError('An error occurred while searching for packages.'); + } + }; + + // Fetch rating for a specific package + const fetchRating = async (packageId: string) => { + setError(null); + setRatingData(null); + + try { + const response = await fetch(`/ratings?packageId=${encodeURIComponent(packageId)}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (response.ok) { + const data: RatingData = await response.json(); + setRatingData(data); + } else { + setError('Failed to fetch rating. Please try again.'); + } + } catch (err) { + console.error('Error fetching rating:', err); + setError('An error occurred while fetching the rating.'); + } + }; + + const handleNextPage = () => { + handleSearch(offset + 1); // Move to the next page + }; + + const handlePreviousPage = () => { + if (offset > 0) handleSearch(offset - 1); // Move to the previous page if possible }; return ( -
+ { e.preventDefault(); handleSearch(0); }} style={{ maxWidth: '500px', margin: '0 auto' }}>
-
- {packageName && ( + {error &&

{error}

} + + {packages.length > 0 ? ( +
+

Available Packages:

+
    + {packages.map((pkg) => ( +
  • + {pkg.Name} + +
  • + ))} +
+ +
+ + Current Page: {offset + 1} + +
+
+ ) : ( +

No packages found. Try a different search term.

+ )} + + {ratingData && (
-

Rating for: {packageName}

+

Rating Details

Overall Rating: {ratingData.overall} / 5

Dependency Pinning: {ratingData.dependencyPinning.toFixed(2)}

Code Review Metric: {ratingData.codeReviewMetric.toFixed(2)}

@@ -48,4 +197,4 @@ const RatingPage: React.FC = () => { ); }; -export default RatingPage; +export default RatingPage; \ No newline at end of file