Skip to content

Conversation

@Yashgupta9330
Copy link
Contributor

Resolves #928

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced chapter map displays now offer refined views, with the home page title updated to "OWASP Chapters Worldwide" and improved map behavior across detail pages.
    • The search experience has been enriched to include event suggestions with quick navigation.
    • User profiles display additional details—email and location—for a clearer presentation.
    • Release entries now feature direct links for easier access.
  • Chores

    • Updated UI dependencies and streamlined build workflows enhance overall stability.

Walkthrough

The changes introduce a new prop, showLocal, to the ChapterMap component across multiple files, affecting how local chapters are displayed on the map. The Home, Chapters, and CardDetailsPage components are updated to pass this new prop with different values. Additionally, the UserCard and MultiSearchBar components are modified to include new properties and functionalities. The package.json file is updated for a dependency version, and changes are made to GraphQL queries and models to accommodate new fields.

Changes

File(s) Change Summary
frontend/src/components/ChapterMap.tsx Added a new prop showLocal, updated logic for marker handling, simplified map view adjustments based on showLocal, and modified the dependency array for useEffect.
frontend/src/pages/Home.tsx Updated section title from "OWASP Chapters Nearby" to "OWASP Chapters Worldwide" and added showLocal prop to ChapterMap with a value of false. Repositioned TopContributors component.
frontend/src/pages/Chapters.tsx Introduced showLocal prop with a value of true to ChapterMap, conditionally displayed based on chapters array length.
frontend/src/components/CardDetailsPage.tsx Added showLocal prop set to true in ChapterMap conditional rendering block.
frontend/src/components/UserCard.tsx Updated props to include email and location, modified rendering logic to display these properties, and changed class names for styling adjustments.
frontend/src/components/MultiSearch.tsx Enhanced search functionality to include eventData, modified debouncedSearch and handleSuggestionClick functions to integrate event suggestions.
frontend/src/types/card.ts Updated UserCardProps interface to include new properties: email and location.
frontend/src/types/search.ts Modified MultiSearchBarProps to include eventData, and updated Suggestion interface to allow hits to include EventType[].
frontend/package.json Updated @ark-ui/react dependency version from ^5.0.0 to ^5.0.1.
backend/apps/github/graphql/nodes/release.py Added a new field url to ReleaseNode class and created a resolver for it.
backend/apps/github/models/release.py Introduced a new property method url in Release class to construct release URLs.
backend/tests/github/graphql/nodes/release_test.py Added "url" to the expected_fields in the test_meta_configuration method to validate its presence in ReleaseNode.

Possibly related PRs

  • frontend for snapshotDetailsPage #981: The changes in the main PR, specifically the addition of the showLocal prop to the ChapterMap component, are related to the changes in the retrieved PR, which also involves the SnapshotDetailsPage that utilizes the ChapterMap component. Both PRs modify the same component, indicating a direct connection at the code level.

Suggested labels

frontend-tests

Suggested reviewers

  • kasya

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff8d3c4 and 3e5e00b.

📒 Files selected for processing (5)
  • frontend/__tests__/unit/pages/Home.test.tsx (2 hunks)
  • frontend/__tests__/unit/pages/Home.test.tsx (2 hunks)
  • frontend/__tests__/unit/pages/Home.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/Home.test.tsx (1 hunks)
  • frontend/src/pages/SnapshotDetails.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: CodeQL (python)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
🔇 Additional comments (2)
frontend/__tests__/unit/pages/Home.test.tsx (1)

7-7: Appropriate import for formatDate utility

The import of formatDate from 'utils/dateFormatter' is correctly added for use in the new test case.

frontend/src/pages/SnapshotDetails.tsx (1)

147-151:

✅ Verification successful

Ensure consistency with PR objectives when setting showLocal prop.

The addition of showLocal={false} to the ChapterMap component is consistent with other similar uses in the codebase (like the Home page), but consider verifying whether this setting aligns with the PR's core objective of "rendering all chapters on the map and adjusting zoom level based on user's IP coordinates."

Since this page displays snapshot-specific chapters rather than all chapters, setting showLocal={false} is likely appropriate here. However, it's worth confirming that this doesn't impact the visibility requirements for chapter data specific to snapshots.


🏁 Script executed:

#!/bin/bash
# Check how showLocal prop is implemented in ChapterMap component
cat frontend/src/components/ChapterMap.tsx | grep -A 20 showLocal

Length of output: 1317


Verified consistency of showLocal usage in SnapshotDetails with ChapterMap’s behavior.

After reviewing the implementation of the showLocal prop in ChapterMap (which only triggers local zoom adjustments when set to true), setting it to false in SnapshotDetails aligns with the intent for snapshot-specific chapter displays. This page isn’t meant to apply the “local” trimming/zoom logic used elsewhere (such as on the Home page), so the current configuration appears appropriate.

Please verify that the default map view (when showLocal is false) meets the design objectives regarding rendering all snapshot chapters and the desired zoom level based on user IP coordinates.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Yashgupta9330 Yashgupta9330 marked this pull request as draft March 4, 2025 13:10
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
frontend/src/components/ChapterMap.tsx (2)

9-19: Consider adding a utility function for the Haversine formula.

The Haversine formula implementation is correct, but it would be better to move this function to a utility file since it's a general geographic calculation that could be reused elsewhere in the application.

Move this function to a dedicated utility file:

// Create a new file: frontend/src/utils/geoUtils.ts
+ /**
+  * Calculates the distance between two geographic coordinates using the Haversine formula
+  * @param lat1 Latitude of first point in decimal degrees
+  * @param lng1 Longitude of first point in decimal degrees
+  * @param lat2 Latitude of second point in decimal degrees
+  * @param lng2 Longitude of second point in decimal degrees
+  * @returns Distance in kilometers
+  */
+ export const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
+   const R = 6371 // Earth's radius in km
+   const dLat = ((lat2 - lat1) * Math.PI) / 180
+   const dLng = ((lng2 - lng1) * Math.PI) / 180
+   const a =
+     Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+     Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) *
+     Math.sin(dLng / 2) * Math.sin(dLng / 2)
+   const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
+   return R * c
+ }

Then in the ChapterMap component:

import L from 'leaflet'
import React, { useEffect, useMemo, useRef } from 'react'
import 'leaflet/dist/leaflet.css'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'
import { GeoLocDataAlgolia, GeoLocDataGraphQL } from 'types/chapter'
+ import { getDistance } from 'utils/geoUtils'

- const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {
-   const R = 6371
-   const dLat = ((lat2 - lat1) * Math.PI) / 180
-   const dLng = ((lng2 - lng1) * Math.PI) / 180
-   const a =
-     Math.sin(dLat / 2) * Math.sin(dLat / 2) +
-     Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) *
-     Math.sin(dLng / 2) * Math.sin(dLng / 2)
-   const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
-   return R * c
- }

93-115: Consider adding visual distinction for nearest chapters.

While you're correctly processing the nearest chapters, they don't have any visual distinction on the map compared to other chapters.

Add visual distinction for the nearest chapters to improve user experience:

validChapters.forEach((chapter) => {
+  // Check if this is one of the nearest chapters
+  const isNearestChapter = userLocation && 
+    nearestChapters.some(nc => nc.key === chapter.key);
+
+  // Use a different icon for nearest chapters
  const markerIcon = new L.Icon({
    iconAnchor: [12, 41],
    iconRetinaUrl: '/img/marker-icon-2x.png',
    iconSize: [25, 41],
-   iconUrl: '/img/marker-icon.png',
+   iconUrl: isNearestChapter ? '/img/marker-icon-nearest.png' : '/img/marker-icon.png',
    popupAnchor: [1, -34],
    shadowSize: [41, 41],
    shadowUrl: '/img/marker-shadow.png',
  })
  const marker = L.marker([chapter.lat, chapter.lng], { icon: markerIcon })
  const popup = L.popup()
  const popupContent = document.createElement('div')
  popupContent.className = 'popup-content'
-  popupContent.textContent = chapter.name
+  
+  // Add distance information for nearest chapters
+  if (isNearestChapter && userLocation) {
+    const nearestChapter = nearestChapters.find(nc => nc.key === chapter.key);
+    const distance = nearestChapter?.distance?.toFixed(1) || 0;
+    popupContent.innerHTML = `<strong>${chapter.name}</strong><br>${distance} km from your location`;
+  } else {
+    popupContent.textContent = chapter.name;
+  }

Note: You'll need to create a new marker icon file for nearest chapters or use a different approach for visual distinction.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2360b30 and e33a663.

📒 Files selected for processing (2)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (4 hunks)
🔇 Additional comments (5)
frontend/src/pages/Chapters.tsx (1)

113-113: LGTM! The userLocation prop is correctly passed to ChapterMap.

The userLocation state is properly passed to the ChapterMap component, allowing it to use this information for chapter sorting and map display.

frontend/src/components/ChapterMap.tsx (4)

41-52: Excellent implementation of the nearest chapters calculation with useMemo.

The implementation of nearestChapters is well done, using useMemo for performance optimization and properly handling the case when userLocation is null. The sorting by distance and limiting to the closest 5 chapters is a good approach.


82-91: Good validation of chapter coordinates.

The thorough validation of chapter coordinates before processing them is excellent. This helps prevent mapping issues with invalid coordinates and improves the robustness of the application.


119-134: Well-implemented map bounds fitting with fallbacks.

The bounds fitting logic with multiple fallbacks is well-implemented. The try-catch block provides good error handling for edge cases.


135-135: Don't forget to update dependency array for useEffect.

You've correctly updated the dependency array to include the new nearestChapters and userLocation variables, ensuring the effect runs when these values change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
frontend/src/components/ChapterMap.tsx (3)

9-19: Good implementation of the Haversine formula for distance calculation.

The getDistance function correctly implements the Haversine formula to calculate the great-circle distance between two geographic points. This is the appropriate mathematical approach for determining the distance between coordinates on Earth's surface.

Consider adding JSDoc comments to document this function's purpose, parameters, and return value:

+/**
+ * Calculates the distance between two geographical points using the Haversine formula
+ * @param lat1 - Latitude of the first point in decimal degrees
+ * @param lng1 - Longitude of the first point in decimal degrees
+ * @param lat2 - Latitude of the second point in decimal degrees
+ * @param lng2 - Longitude of the second point in decimal degrees
+ * @returns Distance between the points in kilometers
+ */
const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {

81-91: Consider extracting validChapters to a useMemo hook.

The filtering of valid chapters is currently done inside the useEffect, but it only depends on normalizedData. Moving this calculation into a useMemo hook would prevent unnecessary recalculation when other dependencies change.

const normalizedData = useMemo(() => {
  return geoLocData.map((chapter) => ({
    lat: '_geoloc' in chapter ? chapter._geoloc.lat : chapter.geoLocation.lat,
    lng: '_geoloc' in chapter ? chapter._geoloc.lng : chapter.geoLocation.lng,
    key: chapter.key,
    name: chapter.name,
  }))
}, [geoLocData])

+ const validChapters = useMemo(() => {
+   return normalizedData.filter(chapter =>
+     chapter.lat !== null &&
+     chapter.lng !== null &&
+     !isNaN(chapter.lat) &&
+     !isNaN(chapter.lng) &&
+     chapter.lat >= -90 &&
+     chapter.lat <= 90 &&
+     chapter.lng >= -180 &&
+     chapter.lng <= 180
+   )
+ }, [normalizedData])

useEffect(() => {
  // ...existing code...
  
  const markerClusterGroup = L.markerClusterGroup()
  const bounds: [number, number][] = []
  
-  // Validate and filter out invalid coordinates
-  const validChapters = normalizedData.filter(chapter =>
-    chapter.lat !== null &&
-    chapter.lng !== null &&
-    !isNaN(chapter.lat) &&
-    !isNaN(chapter.lng) &&
-    chapter.lat >= -90 &&
-    chapter.lat <= 90 &&
-    chapter.lng >= -180 &&
-    chapter.lng <= 180
-  )

  validChapters.forEach((chapter) => {
    // ...existing code...
  })
  
  // ...rest of the effect...
-}, [normalizedData, nearestChapters, userLocation])
+}, [validChapters, nearestChapters, userLocation])

Also applies to: 93-115


41-52: Consider adding a configurable limit for nearest chapters.

The nearest chapters are currently hard-limited to 5. Consider making this a configurable prop to allow more flexibility in different contexts.

const ChapterMap = ({
  geoLocData,
  userLocation,
  style,
+ nearestLimit = 5,
}: {
  geoLocData: GeoLocDataGraphQL[] | GeoLocDataAlgolia[]
  userLocation: { lat: number; lng: number } | null
  style: React.CSSProperties
+ nearestLimit?: number
}) => {
  // ...existing code...

  const nearestChapters = useMemo(() => {
    if (!userLocation) return normalizedData

    // Sort chapters by distance from user location
    return normalizedData
      .map((chapter) => ({
        ...chapter,
        distance: getDistance(userLocation.lat, userLocation.lng, chapter.lat, chapter.lng),
      }))
      .sort((a, b) => a.distance - b.distance)
-     .slice(0, 5)
+     .slice(0, nearestLimit)
  }, [userLocation, normalizedData, nearestLimit])

  // ...rest of component...
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e33a663 and a9f6f15.

📒 Files selected for processing (1)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
🔇 Additional comments (10)
frontend/src/components/ChapterMap.tsx (10)

21-29: Props interface update correctly extends functionality.

The addition of the userLocation prop with proper typing allows the component to receive the user's geographical coordinates, enabling the proximity-based sorting feature.


41-52: Well-implemented nearest chapters calculation with useMemo.

The useMemo hook efficiently calculates the nearest chapters based on user location, with proper handling of the case when user location is unavailable. The logic correctly:

  1. Maps over chapters to calculate distances
  2. Sorts by increasing distance
  3. Limits results to the 5 nearest chapters

This optimizes performance by only recalculating when dependencies change.


57-58: Map initialization parameter adjustment.

Setting worldCopyJump to false prevents the map from wrapping around the world when panning, which is generally appropriate for this use case.


59-61: Map bounds correctly defined.

The maxBounds property is correctly set to encompass the entire world with proper latitude (-90 to 90) and longitude (-180 to 180) ranges.


81-91: Excellent implementation of coordinate validation.

The validation logic thoroughly checks for invalid coordinates by ensuring values:

  • Are not null
  • Are not NaN
  • Fall within valid latitude (-90 to 90) and longitude (-180 to 180) ranges

This prevents map rendering issues and improves robustness against bad data.


93-93: Properly updated to use validated chapters.

The code now correctly iterates only over chapters with valid coordinates.


95-102: Icon configuration improvement.

The marker icon configuration has been refined with properly defined dimensions and anchor points.


119-134: Robust bounds fitting with appropriate fallback mechanisms.

The enhanced bounds fitting logic provides a user-focused experience by:

  1. Prioritizing nearest chapters when user location is available
  2. Falling back to all chapters if nearest chapters can't be used
  3. Defaulting to a preset view if all else fails

The try-catch block properly handles potential errors that might occur during bounds fitting.


135-135: Updated useEffect dependencies correctly reflect new data dependencies.

The useEffect hook now properly depends on nearestChapters and userLocation in addition to normalizedData, ensuring it runs when any of these values change.


137-137: Simplified return statement.

The return statement has been cleaned up for better readability.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
frontend/src/pages/Chapters.tsx (1)

111-111: Consider providing a loading state indication for geolocation.

The userLocation prop is passed to the ChapterMap component without any indication of whether the location is being fetched or if there was an error. This can lead to confusion for users who may be waiting for the map to center on their location.

Add a loading state indication:

<ChapterMap
  geoLocData={searchQuery ? chapters : geoLocData}
- userLocation={userLocation}
+ userLocation={userLocation}
+ isLoadingLocation={isRequestingLocation}
+ locationError={locationError}
  style={{ height: '400px', width: '100%', zIndex: '0' }}
/>

Then update the ChapterMap component to handle these props and display appropriate UI elements.

frontend/src/components/ChapterMap.tsx (3)

9-21: Enhance distance calculation with type validation and constant documentation.

The Haversine formula implementation looks good, but could benefit from additional documentation and type validation:

const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {
-  const R = 6371
+  // Earth radius in kilometers
+  const R = 6371

+  // Convert degrees to radians
  const dLat = ((lat2 - lat1) * Math.PI) / 180
  const dLng = ((lng2 - lng1) * Math.PI) / 180

+  // Haversine formula calculation
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos((lat1 * Math.PI) / 180) *
      Math.cos((lat2 * Math.PI) / 180) *
      Math.sin(dLng / 2) *
      Math.sin(dLng / 2)
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  return R * c
}

43-54: Make the number of nearest chapters configurable and add distance display.

The current implementation hardcodes the number of nearest chapters to 5. Consider making this configurable and showing the distance to the user:

const nearestChapters = useMemo(() => {
  if (!userLocation) return normalizedData

+  // Number of nearest chapters to display
+  const maxNearestChapters = 5

  // Sort chapters by distance from user location
  return normalizedData
    .map((chapter) => ({
      ...chapter,
      distance: getDistance(userLocation.lat, userLocation.lng, chapter.lat, chapter.lng),
    }))
    .sort((a, b) => a.distance - b.distance)
-    .slice(0, 5)
+    .slice(0, maxNearestChapters)
}, [userLocation, normalizedData])

Also consider exposing the distance in the popup to provide users with valuable information:

// Inside the forEach loop where popups are created
const popupContent = document.createElement('div')
popupContent.className = 'popup-content'
- popupContent.textContent = chapter.name
+ popupContent.innerHTML = `
+   <strong>${chapter.name}</strong>
+   ${chapter.distance !== undefined ? `<p>Distance: ${Math.round(chapter.distance)} km</p>` : ''}
+ `

84-94: Add logging for invalid coordinates to help with data quality.

The validation logic for filtering out invalid coordinates is excellent. To further improve data quality, consider adding logging for invalid coordinates that are filtered out:

// Validate and filter out invalid coordinates
const validChapters = normalizedData.filter(
  (chapter) => {
+    const isValid = 
      chapter.lat !== null &&
      chapter.lng !== null &&
      !isNaN(chapter.lat) &&
      !isNaN(chapter.lng) &&
      chapter.lat >= -90 &&
      chapter.lat <= 90 &&
      chapter.lng >= -180 &&
      chapter.lng <= 180
+    
+    if (!isValid) {
+      console.warn(`Invalid coordinates for chapter ${chapter.name}: lat=${chapter.lat}, lng=${chapter.lng}`)
+    }
+    
+    return isValid
  }
)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a9f6f15 and c117eed.

📒 Files selected for processing (2)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (python)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: Run backend tests
🔇 Additional comments (4)
frontend/src/pages/Chapters.tsx (3)

17-17: Add location consent mechanism and error handling.

While adding the user location state is a good addition, it's important to address privacy and user experience concerns. Currently, the application requests the user's location without explaining why or handling potential errors.

Enhance the user location handling by adding error state and user consent:

- const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null)
+ const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null)
+ const [locationError, setLocationError] = useState<string | null>(null)
+ const [locationConsent, setLocationConsent] = useState<boolean>(false)

50-59: Implement error handling and user feedback for geolocation.

The current implementation doesn't handle geolocation errors, which can occur if the user denies permission or if the browser can't determine location. Additionally, there's no indication to users why their location is being requested.

Add error handling and improve the user experience:

const fetchUserLocation = () => {
-  if (navigator.geolocation) {
+  if (navigator.geolocation && locationConsent) {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        setUserLocation({
          lat: position.coords.latitude,
          lng: position.coords.longitude,
        })
+       setLocationError(null)
      },
+     (error) => {
+       setLocationError(
+         error.code === 1
+           ? 'Location permission denied. Chapters will not be sorted by proximity.'
+           : 'Unable to retrieve your location. Chapters will not be sorted by proximity.'
+       )
+       console.error('Geolocation error:', error)
+     },
+     { timeout: 10000, maximumAge: 60000 }
    )
+  } else if (!navigator.geolocation) {
+    setLocationError('Geolocation is not supported by your browser. Chapters will not be sorted by proximity.')
  }
}

62-62: Add conditional location fetching based on user consent.

Rather than automatically fetching the user's location on component mount, it's better to request user consent first due to privacy considerations.

Update the implementation to request user consent before fetching location:

fetchData()
- fetchUserLocation()
+ // Location will be fetched after user provides consent through a UI control

Then add a consent UI in the return statement:

{!locationConsent && !locationError && (
  <div className="geolocation-consent">
    <p>Enable location services to find chapters near you?</p>
    <button 
      onClick={() => {
        setLocationConsent(true);
        fetchUserLocation();
      }}
    >
      Allow
    </button>
    <button onClick={() => setLocationError('Location access declined.')}>
      Decline
    </button>
  </div>
)}
{locationError && (
  <div className="geolocation-error">{locationError}</div>
)}
frontend/src/components/ChapterMap.tsx (1)

123-139: Well-structured fallback mechanism for map bounds.

The implementation of a fallback mechanism for fitting map bounds is well-structured and handles various scenarios gracefully:

  1. If user location is available, it attempts to fit the bounds to the nearest chapters
  2. If that fails, it falls back to fitting the bounds of all valid chapters
  3. If all else fails, it defaults to a preset view

This ensures a good user experience in all scenarios. Great job!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
frontend/src/pages/Chapters.tsx (3)

17-17: 🛠️ Refactor suggestion

Add location consent mechanism

Adding user location tracking without explicit consent violates privacy best practices. This should be combined with a user consent mechanism and proper error handling.

Follow the previous review suggestion to add location consent:

+ const [locationConsent, setLocationConsent] = useState<boolean>(false)
+ const [locationError, setLocationError] = useState<string | null>(null)
const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null)

54-68: 🛠️ Refactor suggestion

Implement comprehensive geolocation error handling

The current implementation catches errors but doesn't provide user feedback or handle location permission denials appropriately.

Implement proper error handling as previously suggested:

const fetchUserLocation = () => {
-  if (navigator.geolocation) {
+  if (navigator.geolocation && locationConsent) {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        setUserLocation({
          lat: position.coords.latitude,
          lng: position.coords.longitude,
        })
+       setLocationError(null)
      },
      (error) => {
-        console.warn('Geolocation error:', error)
+        setLocationError(
+          error.code === 1
+            ? 'Location permission denied. Chapters will not be sorted by proximity.'
+            : 'Unable to retrieve your location. Chapters will not be sorted by proximity.'
+        )
+        console.error('Geolocation error:', error)
      },
+     { timeout: 10000, maximumAge: 60000 }
    )
+  } else if (!navigator.geolocation) {
+    setLocationError('Geolocation is not supported by your browser. Chapters will not be sorted by proximity.')
  }
}
🧰 Tools
🪛 GitHub Actions: Run CI/CD

[error] 64-64: ESLint: Unexpected console statement (no-console)


70-71: 🛠️ Refactor suggestion

Request user consent before fetching location

Automatically fetching user location on component mount violates privacy best practices. This should only happen after explicit user consent.

fetchChapterData()
- fetchUserLocation()
+ // Location will be fetched after user provides consent through a UI control

And add a consent UI component in the return statement:

{!locationConsent && !locationError && (
  <div className="geolocation-consent">
    <p>Enable location services to find chapters near you?</p>
    <button 
      onClick={() => {
        setLocationConsent(true);
        fetchUserLocation();
      }}
    >
      Allow
    </button>
    <button onClick={() => setLocationError('Location access declined.')}>
      Decline
    </button>
  </div>
)}
{locationError && (
  <div className="geolocation-error">{locationError}</div>
)}
🧹 Nitpick comments (1)
frontend/src/components/ChapterMap.tsx (1)

9-21: Improve Haversine distance calculation function readability

The getDistance function correctly implements the Haversine formula but could be improved for readability and maintainability.

const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {
-  const R = 6371
+  // Earth's radius in kilometers
+  const EARTH_RADIUS_KM = 6371
+  
+  // Convert latitude and longitude from degrees to radians
+  const lat1Rad = (lat1 * Math.PI) / 180
+  const lat2Rad = (lat2 * Math.PI) / 180
+  const latDiffRad = ((lat2 - lat1) * Math.PI) / 180
+  const lngDiffRad = ((lng2 - lng1) * Math.PI) / 180
-  const dLat = ((lat2 - lat1) * Math.PI) / 180
-  const dLng = ((lng2 - lng1) * Math.PI) / 180
  const a =
-    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
-    Math.cos((lat1 * Math.PI) / 180) *
-      Math.cos((lat2 * Math.PI) / 180) *
-      Math.sin(dLng / 2) *
-      Math.sin(dLng / 2)
+    Math.sin(latDiffRad / 2) * Math.sin(latDiffRad / 2) +
+    Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(lngDiffRad / 2) * Math.sin(lngDiffRad / 2)
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
-  return R * c
+  return EARTH_RADIUS_KM * c
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c117eed and 18d706d.

📒 Files selected for processing (2)
  • frontend/src/components/ChapterMap.tsx (3 hunks)
  • frontend/src/pages/Chapters.tsx (6 hunks)
🧰 Additional context used
🪛 GitHub Actions: Run CI/CD
frontend/src/pages/Chapters.tsx

[error] 50-50: ESLint: Unexpected console statement (no-console)


[error] 64-64: ESLint: Unexpected console statement (no-console)

🔇 Additional comments (6)
frontend/src/pages/Chapters.tsx (2)

106-108: Good use of useMemo for performance optimization

Using useMemo for mapData is a good practice as it avoids unnecessary recalculations when dependencies don't change.


123-127: Good conditional rendering with proper props

The conditional rendering of ChapterMap and passing of the relevant props is implemented correctly.

frontend/src/components/ChapterMap.tsx (4)

24-30: Properly defined props with clear typing

The props for the ChapterMap component are well defined with appropriate types and default values.


44-54: Well implemented nearest chapters calculation

The nearestChapters calculation correctly uses the distance function, handles the null case gracefully, and uses useMemo for performance optimization.


84-94: Robust coordinate validation

The coordinate validation is thorough and prevents errors from invalid data. It checks for null values, NaN, and ensures coordinates are within valid geographical ranges.


124-141: Excellent progressive fallback strategy for map bounds

The implementation uses a smart progressive fallback strategy:

  1. First tries to focus on nearest chapters if user location is available
  2. Falls back to all chapters if nearest chapters aren't available
  3. Defaults to a global view if bounds fitting fails

This ensures a good user experience in all scenarios.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
frontend/src/components/ChapterMap.tsx (3)

9-21: Excellent implementation of the Haversine formula for distance calculation.

The getDistance function correctly implements the Haversine formula to calculate the great-circle distance between two geographical points. The implementation uses the proper mathematical constants and transformations to compute distances in kilometers.

Consider adding a simple JSDoc comment above the function to explain that it calculates the distance in kilometers and uses the Haversine formula. This would improve documentation for future developers working with this code.


57-61: Consider documenting the worldCopyJump property decision.

The worldCopyJump property is set to false, which prevents the map from wrapping around the dateline. This is a reasonable choice for a chapter map with specific locations, but it might be worth adding a brief comment explaining this decision, especially if it represents a change from previous behavior.


126-144: Excellent map view management with proper fallback mechanism.

The map view determination follows a smart prioritization approach:

  1. First tries to display nearest chapters when user location is available
  2. Falls back to showing all chapters if no user location
  3. Provides a sensible default view if bounds fitting fails

This creates a good user experience with graceful degradation.

Consider extracting the bounds fitting logic to a separate function to improve readability, something like:

const fitMapToAppropriateView = (map: L.Map) => {
  try {
    if (userLocation && nearestChapters.length > 0) {
      const nearestBounds = nearestChapters.map(
        (chapter) => [chapter.lat, chapter.lng] as [number, number]
      )
      map.fitBounds(nearestBounds, {
        maxZoom: 10,
        padding: [50, 50],
      })
    } else if (bounds.length > 0) {
      map.fitBounds(bounds)
    }
  } catch {
    map.setView([20, 0], 2)
  }
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57ba179 and 5506cd2.

📒 Files selected for processing (1)
  • frontend/src/components/ChapterMap.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
🔇 Additional comments (8)
frontend/src/components/ChapterMap.tsx (8)

23-30: Properly typed prop addition for user location.

The addition of the userLocation optional prop with appropriate TypeScript typing is well-implemented. This change enables the component to handle geolocation-based features.


44-54: Well-implemented nearest chapters calculation with proper memoization.

The nearestChapters implementation efficiently:

  1. Handles the null/undefined case for userLocation
  2. Calculates distances only when necessary
  3. Sorts chapters by proximity
  4. Limits to 5 nearest chapters for better user experience

The useMemo hook correctly specifies dependencies to prevent unnecessary recalculations.


62-64: Map bounds setting is properly configured.

The maxBounds setting correctly defines the entire globe as the boundary (latitude -90 to 90, longitude -180 to 180).


75-83: Good cleanup pattern for marker cluster group.

The code properly removes any existing marker cluster group before creating a new one, which prevents accumulation of markers and potential memory leaks or visual artifacts.


86-97: Robust validation for chapter coordinates.

The validation logic thoroughly checks for:

  1. Null values
  2. NaN values
  3. Valid latitude range (-90 to 90)
  4. Valid longitude range (-180 to 180)

This prevents potential rendering issues or errors from invalid geographical data.


99-122: Well-structured marker creation with appropriate configuration.

The marker creation logic is well-implemented with proper icon configuration and event handling. The addition of markers only for valid chapters ensures map stability.


145-145: Correctly updated useEffect dependencies.

The useEffect dependency array properly includes nearestChapters and userLocation since these values are now used within the effect. This ensures the effect runs when these values change.


147-147: Clean component rendering.

The component rendering is clean and straightforward, maintaining a simple structure for the map container.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
frontend/src/components/ChapterMap.tsx (5)

55-56: Ensure proper cleanup for the marker cluster reference.
When the component unmounts, consider removing layers or resetting markerClusterRef.current to avoid potential stale references.


57-68: Robust coordinate validation approach.
Filtering out invalid or out-of-bounds lat/lng values before rendering markers improves stability and prevents runtime errors. You could refactor this filter into a small helper function if it’s needed elsewhere for improved reusability.


99-111: Consider generalizing fixed “6th chapter” logic.
Targeting only the 6th chapter and fitting bounds around the first 6 might be a strict requirement, but if this logic changes in the future (e.g., highlight the 10th, 20th, etc.), you could introduce a configurable parameter or an auto-center approach.


120-122: Consider user-facing error handling.
Catching and logging errors is great, but you might also consider informing users when the map cannot render properly, instead of silently defaulting the view.


126-126: Return statement with static ID.
Returning a single <div id="chapter-map"/> is fine if only one map is used on each page. If multiple maps might appear later, consider unique IDs or dynamic approach.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5506cd2 and 19bafd6.

📒 Files selected for processing (2)
  • frontend/src/components/ChapterMap.tsx (3 hunks)
  • frontend/src/pages/Chapters.tsx (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/pages/Chapters.tsx
🔇 Additional comments (6)
frontend/src/components/ChapterMap.tsx (6)

17-17: Good addition of markerClusterRef for improved cluster management.
This reference allows you to conveniently manage marker clusters and access cluster-specific methods. Ensure that you reset or clean up the cluster group on component unmount if needed to prevent memory leaks.


31-34: Check whether worldCopyJump: false aligns with your desired user map experience.
By setting maxBounds to the entire globe and disabling worldCopyJump, the map will not horizontally wrap. This prevents users from smoothly panning across the 180° meridian boundary, which may or may not be preferable depending on the project's requirements.


52-52: Informative comment.
The explanatory comment “Create a new marker cluster group” is clear, concise, and helpful for maintainers.


70-81: Marker creation logic is solid, with well-structured icon configuration.
Using a custom icon and binding popups individually is clear. Verify that the icon asset paths (/img/marker-icon.png, etc.) are correct in production builds.


97-98: Clear documentation.
Writing a concise comment (“Determine map view based on 6th index”) keeps future maintainers informed of your logic.


112-119: Well-structured fallback logic for fewer than six chapters.
Gradually narrowing down through different scenarios (>=6, >0, etc.) is readable. Ensure testing covers each branch, especially edge cases with no valid chapters.

@kasya
Copy link
Collaborator

kasya commented Mar 9, 2025

@arkid15r @kasya is this right?

@Yashgupta9330 Looks good on the video! Will review today 👍🏼

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!
Just want to clarify some things! ⬇️

if (bounds.length > 0) {
map.fitBounds(bounds as L.LatLngBoundsExpression, { maxZoom: 10 })
// Determine map view based on 6th index (index 5)
try {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate a bit more on the logic in this block? I think it works, but I'm just not sure what's going on.
Why do we set view to a sixth chapter? Why not 1st for example? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose the sixth location as the reference point for the default zoom because the data is sorted in a way where the sixth location provides a good central point to cover the surrounding five locations on the map. Zooming to this position ensures that all five prior locations are visible while still maintaining an optimal view of the area. Using the first index would focus too much on a single location, potentially causing some of the other important locations to be out of the initial zoom view.

query: '',
currentPage: 1,
hitsPerPage: 25,
hitsPerPage: 1000,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we increase this so much? 🤔

Copy link
Contributor Author

@Yashgupta9330 Yashgupta9330 Mar 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because I want to show all chapter also previously only 5 chapters was fetching

@Yashgupta9330 Yashgupta9330 requested a review from kasya March 9, 2025 02:45
@arkid15r
Copy link
Collaborator

@Yashgupta9330 this PR doesn't address the issue -- it has nothing to do w/ the chapters page and for the main page you just increased the number of chapters shown.

I'm closing this out.

@arkid15r arkid15r closed this Mar 11, 2025
arkid15r and others added 8 commits March 11, 2025 10:08
OWASP#1070)

* correction to overflow of name in usercard

* review resolved

* review resolved new

* company or email or location added

* company or email or location added and interface change

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
…OWASP#1071)

* correct changes

* changes to the links

* corrected linking and reviews correction

* linking resolved

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
* Fetch upcoming events directly from GET_MAIN_PAGE_DATA via GraphQL instead of Algolia. Updated MultiSearchBar to include event results dynamically.

* Update frontend/src/components/MultiSearch.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix And Added Icons

* Performance Fix

* Update code

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Arkadii Yakovets <[email protected]>
@arkid15r arkid15r reopened this Mar 11, 2025
@arkid15r
Copy link
Collaborator

I reworked the logic a bit and how map looks at the main page. I'll file another ticket to improve it on the Chapters page.

arkid15r
arkid15r previously approved these changes Mar 11, 2025
Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try this

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
frontend/src/components/MultiSearch.tsx (1)

58-67: Client-side event filtering implementation.

The implementation filters events based on the search query and adds them to the search results. This approach works well for a reasonable number of events.

Consider adding a comment explaining why client-side filtering is used for events while other entities use Algolia. Also, consider adding case insensitive filtering for other event properties like location or description to improve search relevance.

frontend/src/components/UserCard.tsx (1)

27-31: Consider displaying multiple user properties line by line.
Currently, {company || location || email} displays only the first truthy value. If you intend to show all available data (e.g., company, then location, then email), consider refactoring as shown below:

- <p className="mt-1 max-w-[250px] truncate text-sm text-gray-600 dark:text-gray-400 sm:text-base">
-   {company || location || email}
- </p>
+ <p className="mt-1 max-w-[250px] text-sm text-gray-600 dark:text-gray-400 sm:text-base space-y-1">
+   {company && <span className="block truncate">{company}</span>}
+   {location && <span className="block truncate">{location}</span>}
+   {email && <span className="block truncate">{email}</span>}
+ </p>
frontend/src/pages/Chapters.tsx (2)

32-49: Add error handling to the data fetch.
Consider wrapping fetchAlgoliaData in a try/catch to gracefully handle network or algorithmic failures. For example:

    const fetchData = async () => {
+     try {
        const searchParams = {
          indexName: 'chapters',
          query: '',
          currentPage: 1,
          hitsPerPage: 1000,
        }
        const data: AlgoliaResponseType<ChapterTypeAlgolia> = await fetchAlgoliaData(
          searchParams.indexName,
          searchParams.query,
          searchParams.currentPage,
          searchParams.hitsPerPage
        )
        setGeoLocData(data.hits)
+     } catch (error) {
+       console.error("Failed to fetch data:", error)
+       setGeoLocData([])
+     }
    }

67-81: Consider i18n for the "View Details" label.
A good user experience often includes easily localizable labels. If internationalization is on your roadmap, exposing this label for translation might be beneficial.

frontend/src/components/ChapterMap.tsx (1)

9-19: Consider a standard library for distance calculation.
While this Haversine-based approach is correct, you might use a reliable library (or Leaflet’s utilities) to reduce potential maintenance overhead.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e771d3 and ff8d3c4.

⛔ Files ignored due to path filters (21)
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • backend/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (65)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (4 hunks)
  • frontend/src/components/ChapterMap.tsx (0 hunks)
  • frontend/src/pages/Chapters.tsx (0 hunks)
  • frontend/src/components/ChapterMap.tsx (1 hunks)
  • frontend/src/pages/Chapters.tsx (1 hunks)
  • frontend/package.json (2 hunks)
  • .github/workflows/run-ci-cd.yaml (0 hunks)
  • .github/workflows/run-ci-cd.yaml (0 hunks)
  • frontend/src/pages/Home.tsx (2 hunks)
  • frontend/src/api/queries/homeQueries.ts (2 hunks)
  • frontend/src/components/MultiSearch.tsx (1 hunks)
  • frontend/src/pages/Home.tsx (3 hunks)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (1 hunks)
  • frontend/src/components/ChapterMap.tsx (5 hunks)
  • frontend/src/pages/Chapters.tsx (5 hunks)
  • frontend/src/pages/Chapters.tsx (2 hunks)
  • frontend/src/pages/Chapters.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (2 hunks)
  • frontend/src/components/ChapterMap.tsx (2 hunks)
  • frontend/package.json (3 hunks)
  • frontend/src/components/ChapterMap.tsx (2 hunks)
  • frontend/src/pages/Chapters.tsx (6 hunks)
  • frontend/package.json (1 hunks)
  • frontend/package.json (3 hunks)
  • frontend/package.json (1 hunks)
  • frontend/src/components/ChapterMap.tsx (1 hunks)
  • frontend/src/pages/Chapters.tsx (1 hunks)
  • frontend/src/components/ChapterMap.tsx (1 hunks)
  • frontend/src/components/ChapterMap.tsx (0 hunks)
  • frontend/src/components/UserCard.tsx (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/components/CardDetailsPage.tsx (1 hunks)
  • frontend/src/api/queries/homeQueries.ts (2 hunks)
  • frontend/src/pages/Home.tsx (2 hunks)
  • frontend/src/pages/Home.tsx (1 hunks)
  • frontend/src/api/queries/homeQueries.ts (2 hunks)
  • frontend/src/pages/Home.tsx (2 hunks)
  • frontend/src/pages/Chapters.tsx (0 hunks)
  • frontend/package.json (5 hunks)
  • frontend/package.json (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/components/MultiSearch.tsx (2 hunks)
  • frontend/src/pages/Home.tsx (2 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/components/UserCard.tsx (2 hunks)
  • frontend/src/pages/Users.tsx (1 hunks)
  • frontend/src/types/card.ts (1 hunks)
  • frontend/package.json (3 hunks)
  • backend/apps/github/graphql/nodes/release.py (2 hunks)
  • backend/apps/github/models/release.py (1 hunks)
  • backend/tests/github/graphql/nodes/release_test.py (1 hunks)
  • frontend/src/api/queries/homeQueries.ts (1 hunks)
  • frontend/src/components/MultiSearch.tsx (7 hunks)
  • frontend/src/pages/Home.tsx (1 hunks)
  • frontend/src/types/search.ts (2 hunks)
  • .github/workflows/run-ci-cd.yaml (2 hunks)
  • frontend/package.json (1 hunks)
  • frontend/package.json (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (1 hunks)
  • frontend/src/components/ChapterMap.tsx (4 hunks)
  • frontend/src/pages/Chapters.tsx (1 hunks)
  • frontend/src/pages/Home.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (14)
  • frontend/src/components/ChapterMap.tsx
  • frontend/package.json
  • frontend/package.json
  • frontend/src/pages/Chapters.tsx
  • frontend/src/pages/Chapters.tsx
  • frontend/package.json
  • frontend/src/pages/Chapters.tsx
  • frontend/src/pages/Chapters.tsx
  • frontend/package.json
  • frontend/package.json
  • frontend/package.json
  • frontend/package.json
  • frontend/src/components/MultiSearch.tsx
  • frontend/package.json
🚧 Files skipped from review as they are similar to previous changes (12)
  • frontend/src/components/ChapterMap.tsx
  • frontend/src/components/ChapterMap.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/components/ChapterMap.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/components/ChapterMap.tsx
  • frontend/src/pages/Home.tsx
  • frontend/src/components/ChapterMap.tsx
  • frontend/src/components/ChapterMap.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
frontend/src/pages/Chapters.tsx

[error] 99-99: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 99-99: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Run frontend e2e tests
🔇 Additional comments (35)
frontend/src/types/card.ts (1)

51-52: New user profile properties enhance display capabilities.

The addition of email and location properties to the UserCardProps interface enables the display of more comprehensive user information in the UI.

backend/apps/github/models/release.py (1)

53-56: Good enhancement for linking to GitHub releases.

The url property provides a convenient way to generate GitHub release URLs by combining the repository URL with the release tag name. This implementation follows GitHub's standard URL pattern for releases.

backend/tests/github/graphql/nodes/release_test.py (1)

28-28: Test updated to include the new URL field.

This ensures the GraphQL schema correctly exposes the new url field added to the Release model, maintaining proper test coverage.

frontend/src/components/CardDetailsPage.tsx (1)

70-70:

❓ Verification inconclusive

Setting showLocal for chapter detail map view.

This is a step toward addressing the PR objective of properly displaying chapter information on maps. However, based on the PR objectives, this appears to be only part of the solution.


🌐 Web query:

What is the purpose of the showLocal prop in react-leaflet or similar mapping libraries?

💡 Result:

Based on the provided search results, there is no direct mention of a showLocal prop in React Leaflet or its related documentation. React Leaflet's core components like MapContainer, Marker, TileLayer, and Popup do not include a showLocal prop in their standard APIs[3][9][17].

Possible Interpretations:

  1. Custom Implementation:
    It may refer to a custom prop in a project-specific or third-party component (e.g., controlling visibility of local markers or layers). For example:

    • A component might use showLocal to toggle the display of user location markers or localized data layers.
    • Example syntax (hypothetical):
      <CustomLayerComponent showLocal={true} />
  2. Typo or Misnaming:
    If the intent is to control map visibility or data rendering, similar props in React Leaflet include:

    • whenReady: Triggers a callback when the map initializes[9].
    • Conditional rendering of components (e.g., {showLocal && <LocalLayer />}).
  3. Third-Party Libraries:
    Libraries like leaflet.markercluster or custom wrappers might introduce such a prop for specific behaviors (e.g., clustering local markers)[1][3].

Recommended Approach:

  • Check your component’s documentation or codebase for showLocal usage.
  • For standard React Leaflet behavior, use conditional rendering or Leaflet’s methods like setView to update the map dynamically[6][9].

For further clarification, provide additional context about where you encountered showLocal.

Citations:


Attention: Validate Complete Chapter Map Integration

  • In frontend/src/components/CardDetailsPage.tsx at line 70, the component sets showLocal={true}. Based on our review, this prop is not part of React Leaflet’s standard API and appears to be a custom solution—likely used to control the display of local markers or data layers specific to chapter details.
  • This change is a constructive step toward the PR objective of enhancing chapter information on maps. However, it seems to address only one aspect of the solution. Please verify that any additional logic or complementary functionality needed for full chapter detail mapping is implemented elsewhere in the codebase.
frontend/package.json (1)

94-94:

❓ Verification inconclusive

Verify the TypeScript version update compatibility.

Updating from TypeScript ~5.7.3 to ~5.8.2 is a minor version change that may introduce new features or potentially breaking changes. While keeping dependencies up-to-date is generally good practice, ensure this update doesn't affect the rest of the codebase, especially type definitions.


🏁 Script executed:

#!/bin/bash
# Verify TypeScript version compatibility

# Check for any TypeScript errors with the new version
npx tsc --noEmit
echo "Exit code: $?"

# Check for any TypeScript-specific syntax that might be affected
echo "Checking for potentially affected TypeScript features..."
grep -r "satisfies\|const enum\|infer" --include="*.ts" --include="*.tsx" .

Length of output: 352


Manual Verification Required for TypeScript Upgrade Compatibility

The automated check couldn’t run as expected because the environment lacked the npx command (exit code 127), so the verification of potential TypeScript syntax issues (e.g., usage of satisfies, const enum, or infer) was inconclusive. Please manually verify the following:

  • Confirm that the updated TypeScript version (~5.8.2) compiles your code without errors. For example, run the TypeScript compiler directly (e.g., ./node_modules/.bin/tsc --noEmit) in your local environment.
  • Double-check any TypeScript-specific syntax in your codebase for breaking changes introduced by the minor version update.
  • If you use CI or another automated system, ensure that the TS compiler uses the correct version and that no type definitions are negatively affected.
backend/apps/github/graphql/nodes/release.py (2)

16-16: LGTM! New URL field added to ReleaseNode.

Adding the URL field to the ReleaseNode is a good enhancement that will allow frontend components to link directly to GitHub releases.


31-34:

✅ Verification successful

LGTM! Appropriate resolver implementation.

The resolver implementation is straightforward and follows the pattern used in other resolvers in this class.


🏁 Script executed:

#!/bin/bash
# Verify the new URL field is being used in GraphQL queries

# Check if the url field is referenced in GraphQL queries
echo "Checking GraphQL queries for url field usage:"
grep -r "url" --include="*.graphql" --include="*.py" backend/apps/github/graphql/

Length of output: 1678


LGTM – The release URL resolver is correctly implemented and in sync with its usage in GraphQL queries.

  • The verification confirms that the url field is declared and used appropriately in the release node.
  • The resolver implementation mirrors the pattern used in similar nodes (e.g., repository and user), ensuring consistency across the codebase.

No further changes are necessary.

frontend/src/pages/Home.tsx (4)

18-18: LGTM! Import added for EventType.

The EventType import is properly added to support the new Upcoming Events section.


132-159: New Upcoming Events section added.

This addition provides valuable information to users by displaying upcoming events on the home page. The implementation is well-structured with responsive grid layout and proper date formatting.


58-58: Ensure increasing hitsPerPage is required for showing all chapters.

The value was increased to 1000, which seems excessive. Verify if this large number is necessary for loading all chapters or if a more reasonable limit would be sufficient.


210-214:

✅ Verification successful

Verify that showLocal={false} implements the required chapter map improvements.

Based on the PR objectives, the goal is to render all chapters on the home page map and adjust zoom level based on user location. Ensure that setting showLocal={false} achieves this requirement.


🏁 Script executed:

#!/bin/bash
# Check implementation of ChapterMap component to understand showLocal prop

# Look for ChapterMap implementation
echo "ChapterMap Component Implementation:"
fd "ChapterMap.tsx" frontend/src/components/ --exec cat {}

# Check for other usages of showLocal prop
echo "\nOther usages of showLocal prop:"
grep -r "showLocal" --include="*.tsx" --include="*.ts" frontend/src/

Length of output: 3948


Global Chapter Map View Confirmed

The investigation shows that using showLocal={false} in Home.tsx correctly renders a global map view displaying all chapters. In the ChapterMap component, when showLocal is false, the map initializes with a default view without applying local zoom adjustments. The local zoom logic is applied only when showLocal is true (for example, in Chapters.tsx). This behavior aligns with the PR objectives.

frontend/src/pages/Users.tsx (1)

42-45:

✅ Verification successful

LGTM! Enhanced user information display.

Adding email and location to the UserCard provides more relevant information to users. Ensure the UserCard component properly handles these new props.


🏁 Script executed:

#!/bin/bash
# Verify UserCard component implementation for new props

# Check UserCard implementation
echo "UserCard Component Implementation:"
fd "UserCard.tsx" frontend/src/components/ --exec cat {}

# Check the UserCard props type definition
echo "\nUserCard Props Type Definition:"
grep -r "UserCardProps" --include="*.ts" --include="*.tsx" frontend/src/

Length of output: 3757


UserCard Update Verified: Enhanced User Data Integration

The additions of the email and location props in frontend/src/pages/Users.tsx are correctly handled. The UserCard component in frontend/src/components/UserCard.tsx properly receives and incorporates these props (as confirmed by the component's destructuring and prop-type definition via UserCardProps in frontend/src/types/card.ts). LGTM!

frontend/src/api/queries/homeQueries.ts (2)

45-46: Addition of author login field enhances data completeness.

The addition of the login field to the author object in the recentReleases section is a good improvement, ensuring consistent data structure with other author objects in the query.


52-52: URL field addition allows direct linking to releases.

Adding the url field to the recentReleases section is beneficial for UI implementation, enabling direct navigation to release details.

frontend/src/types/search.ts (3)

2-2: EventType import supports new search functionality.

This import is necessary to support the inclusion of events in search results, aligning with the PR's objective to enhance map functionality.


11-11: New eventData prop enhances MultiSearchBar functionality.

Adding the optional eventData property to MultiSearchBarProps enables the component to receive and process event data for search functionality, which is a valuable enhancement.


16-16: Extended hits type to support event search results.

The type update properly includes EventType[] in the possible types for suggestion hits, ensuring type safety when working with event search results.

.github/workflows/run-ci-cd.yaml (2)

227-227: Improved CI pipeline with E2E test dependency.

Adding the frontend E2E tests as a dependency for the staging build ensures that all frontend functionality (including the chapter map changes) passes end-to-end tests before deployment.


369-369: Enhanced production build safety with E2E test requirement.

Similarly, requiring E2E tests to pass before production builds strengthens the quality assurance process, particularly important for user-facing features like the chapter map.

frontend/src/components/MultiSearch.tsx (9)

7-7: Calendar icon addition supports event search UI.

The addition of the calendar icon provides appropriate visual distinction for event results in the search dropdown.


16-16: EventType import enables event handling in search results.

This import is necessary to properly type and handle event data in the search component.


26-26: New eventData prop supports search integration.

Adding the eventData property to the component props allows passing event information to the search component, enabling event search functionality.


49-54: Updated type definitions for hits to include events.

The type definition updates ensure type safety when working with different entity types in search results, now including events.


75-75: Added eventData to useMemo dependencies.

Correctly adding eventData to the dependency array ensures the debounced search function is updated when event data changes.


85-85: Updated function parameter type to support events.

The type update correctly includes EventType as a possible type for suggestions.


115-118: Updated function call for consistency with type changes.

The function call correctly handles the updated parameter types, ensuring type safety.


194-195: Added icon support for event results.

The implementation correctly associates the calendar icon with event results, providing visual consistency in the UI.


93-95:

✅ Verification successful

Implemented event handling with external URL opening.

The implementation opens event URLs in a new tab, which is appropriate for external event links.

Verify if this is the intended behavior:


🏁 Script executed:

#!/bin/bash
# Check if events are meant to be opened externally by looking at the event URL patterns
# and comparing to how other entity types are handled

# Look for event URL patterns
echo "Checking event URL patterns:"
rg -p "url.*event" --glob "*.ts" --glob "*.tsx"

# Compare with how other entities are handled in navigation
echo "Checking other entity navigation patterns:"
rg -p "navigate\(\`\/.*\`\)" --glob "*.tsx"

Length of output: 612


Verified Event Handling Behavior

The verification confirms that event URLs—such as those found in the test files under frontend/__tests__/e2e/data/mockHomeData.ts and frontend/__tests__/unit/data/mockHomeData.ts—are absolute external links (e.g., https://nest.owasp.org/events/event-1). This corroborates that the window.open((suggestion as EventType).url, '_blank') implementation in frontend/src/components/MultiSearch.tsx (lines 93–95) is correct and appropriate for handling external event links.

  • Event URLs are external absolute URLs (as observed in the mock test data).
  • In-app navigation for other entities typically uses a different approach (e.g., local navigation via helper methods). Although our initial regex test for navigation patterns produced an error, the primary concern with event handling is confirmed by the test data.

No changes are required based on the current verification.

frontend/src/components/UserCard.tsx (1)

6-6: Props usage looks well-organized.
The newly added email and location fields appear consistent with the existing pattern for UserCardProps. No issues found.

frontend/src/pages/Chapters.tsx (3)

1-14: Imports look correct.
Your initial imports, including fetchAlgoliaData and useSearchPage, are clear and consistent.


50-61: Add location consent and error handling.
This code invokes the browser’s geolocation directly without user consent requests or error handling. Similar feedback was provided previously.


111-117: Verify fallback logic for geoLocData acquisition.
When there is no searchQuery, the component relies on geoLocData for the map. Confirm that this flow correctly displays all chapters and satisfies your intended behavior.

frontend/src/components/ChapterMap.tsx (3)

21-29: Map prop definitions appear inconsistent with summary.
The AI-generated summary mentions a showLocal prop, but it’s missing in the final code. Please confirm if you need to add or remove references to showLocal.

Likely an incorrect or invalid review comment.


41-52: Confirm that limiting to 5 nearest chapters aligns with displaying all.
The code sorts chapters by proximity and slices to 5. If the requirement is to display all chapters, then apply bounding to all but still highlight the nearest. Please confirm your intended behavior.


119-135: Bounds fitting logic is robust.
Good job handling map bounds with a fallback for potential errors. The try/catch ensures a graceful default view if bounding fails.

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🛑 Comments failed to post (1)
frontend/__tests__/unit/pages/Home.test.tsx (1)

158-169: 💡 Verification agent

🧩 Analysis chain

Well-structured test for Upcoming Events section

This new test case properly validates the rendering of the "Upcoming Events" section on the Home page, including checking that:

  1. The section title is displayed
  2. Each event name from the mock data is rendered
  3. The formatted date range for each event is displayed correctly

However, I notice that this test doesn't appear to be directly related to the chapter map improvements mentioned in the PR objectives, which focus on rendering all chapters on the home page map and adjusting zoom levels based on the user's location.


🏁 Script executed:

#!/bin/bash
# Check if there are changes to the Home component related to chapter map
rg -A 5 "ChapterMap" frontend/src/pages/Home.tsx

Length of output: 531


Enhance Your Test Suite for Chapter Map Functionality

The Upcoming Events test is well written—it correctly verifies that the events section displays the title, event names, and date ranges. However, the PR objectives also highlight improvements to the chapter map, such as rendering all chapters and adjusting zoom levels based on the user's location. I confirmed via the shell script that the Home component now explicitly renders the ChapterMap (see frontend/src/pages/Home.tsx), but there isn’t any test covering its behavior.

Action Items:

  • Add tests to verify that the ChapterMap component renders with the expected properties.
  • Include checks for correct handling of geolocation data and the dynamic zoom adjustments.

@arkid15r arkid15r merged commit 4edc7f7 into OWASP:main Mar 11, 2025
18 checks passed
shdwcodr pushed a commit to shdwcodr/Nest that referenced this pull request Jun 5, 2025
Improves home page chapter map 

---------
Co-authored-by: Arkadii Yakovets <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve home page chapters map

5 participants