Skip to content

Conversation

mohitb35
Copy link
Collaborator

@mohitb35 mohitb35 commented Nov 8, 2024

  • Improve date formatting by adding string cleanup and zero-padding.
  • Simplify conditional rendering in the KeyInfo component for better readability and maintainability.
  • Correct minor alignment issues in the site dropdown and explore buttons.
  • Allow project details to overflow till bottom of page
  • Potential fix to make sure map resizes as per container dimensions
  • Minor adjustment to position of zoom buttons on mobile (android/iOS) to avoid hiding behind footer
  • Prevent map re-centering when the project filter/search result set is >30 projects long
  • italicises scientific name in sample plant location details
  • formats site area in site dropdown as per locale

Copy link

vercel bot commented Nov 8, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
planet-webapp-multi-tenancy-setup ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 11, 2024 9:31am
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
planet-webapp ⬜️ Ignored (Inspect) Nov 11, 2024 9:31am
planet-webapp-temp ⬜️ Ignored (Inspect) Nov 11, 2024 9:31am

Copy link
Contributor

coderabbitai bot commented Nov 8, 2024

Walkthrough

The pull request introduces several changes across multiple files, including updates to styling in SCSS files, modifications to React components for improved state management, and enhancements to a date formatting utility. Key changes involve the transition from prop-based state management to context-based management for map-related components, as well as adjustments to layout properties and conditional rendering logic. Additionally, the .gitignore file has been updated to exclude specific certificate files.

Changes

File Change Summary
.gitignore Added entries for certificates/localhost-key.pem and certificates/localhost.pem.
src/features/common/Layout/ProjectsLayout/ProjectsLayout.module.scss Updated .mapFeatureExplorerOverlay class to change top property from calc($layoutPaddingTop + 8px) to calc($layoutPaddingTop + 10px).
src/features/projectsV2/ProjectDetails/ProjectDetails.module.scss Updated .projectDetailsContainer height from 100% to calc(100% + 30px) and added padding-bottom: 30px.
src/features/projectsV2/ProjectDetails/components/KeyInfo.tsx Restructured conditional rendering logic using new boolean flags for displaying project information, removing the addZeroToDate function.
src/features/projectsV2/ProjectsMap/MultipleProjectsView.tsx Removed setViewState prop, added useProjectsMap import, and updated view state management to use handleViewStateChange.
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss Introduced new variables $layoutPaddingTop and $layoutPaddingSide for dynamic positioning of .dropdownButton.
src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss Updated .mapContainer to include position: relative and overflow: hidden, adjusted bottom positioning for .android and .ios classes.
src/features/projectsV2/ProjectsMap/SingleProjectView.tsx Renamed setViewState to handleViewStateChange in the SingleProjectView component.
src/features/projectsV2/ProjectsMap/index.tsx Added ViewStateChangeEvent import, updated view state management to use handleViewStateChange, and integrated centering logic into a debounced effect.
src/features/projectsV2/ProjectsMapContext.tsx Introduced ExtendedViewState interface, updated DEFAULT_VIEW_STATE to include width and height, and replaced setViewState with handleViewStateChange.
src/utils/countryCurrency/getFormattedDate.ts Modified formatDate function for improved date handling and error management.
src/utils/mapsV2/zoomToLocation.tsx Updated zoomToLocation function to replace setViewState with handleViewStateChange.
src/utils/mapsV2/zoomToPolygonPlantLocation.tsx Modified zoomToPolygonPlantLocation function to use handleViewStateChange instead of setViewState.
src/utils/mapsV2/zoomToProjectSite.ts Updated zoomInToProjectSite function to replace setViewState with handleViewStateChange, streamlined type handling.
src/utils/projectV2.ts Added new function areMapCoordsEqual for comparing map coordinates, and refined getLocalizedPath function for better path handling.
src/features/projectsV2/ProjectDetails/components/microComponents/PlantInfoCard.tsx Added a new CSS class to the scientificName div and updated rendering logic for the tag property.
src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss Added a nested style rule for .scientificName .data to set font-style to italic.
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/ProjectSiteList.tsx Enhanced site area formatting by incorporating locale-specific formatting using getFormattedRoundedNumber.
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx Integrated locale-based formatting for the site area display in the dropdown.
src/features/projectsV2/ProjectDetails/components/microComponents/SpeciesPlanted.tsx Updated to format treeCount using getFormattedNumber based on current locale.

Possibly related PRs

Suggested labels

MyForest 2.0, PR: unreviewed

Suggested reviewers

  • sunilsabatp

🐇 In the forest where changes bloom,
New styles and logic make room.
With padding and heights, we dance and play,
Enhancing our layout in a joyful way!
From maps to dates, all in a row,
Let's hop along and watch our project grow! 🌱


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

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

🧹 Outside diff range and nitpick comments (16)
src/utils/mapsV2/zoomToLocation.tsx (1)

35-35: Consider adding error handling for the state update.

While the implementation is correct, it might be good to wrap the state update in a try-catch block since it occurs in an event callback. This would help catch and handle any potential errors that might occur during state updates.

-    handleViewStateChange(newViewState);
+    try {
+      handleViewStateChange(newViewState);
+    } catch (error) {
+      console.error('Failed to update view state:', error);
+    }
src/utils/countryCurrency/getFormattedDate.ts (2)

24-26: Consider extracting locale configuration.

The locale configuration is duplicated between string and non-string cases.

Extract the common configuration:

+const getLocaleConfig = () => ({
+  locale: localeMapForDate[localStorage.getItem('language') || 'en'],
+});

 export default function formatDate(date: number | Date | string) {
   // ... existing code ...
   return format(parseISO(isoDateString), 'LLLL d, yyyy', {
-    locale: localeMapForDate[localStorage.getItem('language') || 'en'],
+    ...getLocaleConfig(),
   });
   // ... existing code ...
   return format(date, 'LLLL d, yyyy', {
-    locale: localeMapForDate[localStorage.getItem('language') || 'en'],
+    ...getLocaleConfig(),
   });

5-5: Add JSDoc documentation for the function.

Document the function's behavior, especially:

  • Expected date string format
  • Return value in different scenarios (falsy input, invalid format, error)
  • Locale handling

Add documentation:

+/**
+ * Formats a date into a localized string (e.g., "January 1, 2024")
+ * @param date - Date to format (ISO string YYYY-MM-DD, timestamp, or Date object)
+ * @returns Formatted date string or empty string if invalid/error
+ */
 export default function formatDate(date: number | Date | string) {
src/utils/mapsV2/zoomToPolygonPlantLocation.tsx (1)

Line range hint 12-47: Consider adding input validation.

The function could benefit from additional validation to handle edge cases:

  1. Empty coordinates array
  2. Invalid polygon coordinates that might cause turf.js errors

Consider adding these checks:

 export function zoomToPolygonPlantLocation(
   coordinates: Position[],
   mapRef: MapRef,
   handleViewStateChange: (viewState: Partial<ViewState>) => void,
   duration = 3000
 ) {
   if (!mapRef.current) {
     return;
   }
+  if (!coordinates || coordinates.length < 3) {
+    console.warn('Invalid polygon: At least 3 coordinates required');
+    return;
+  }
+  try {
     const polygon = turf.polygon([coordinates]);
     const bbox = turf.bbox(polygon);
     // ... rest of the implementation
+  } catch (error) {
+    console.error('Failed to process polygon coordinates:', error);
+    return;
+  }
 }
src/utils/mapsV2/zoomToProjectSite.ts (1)

1-4: Rename Map type import to avoid shadowing global Map.

To prevent confusion with the global Map type, consider using a more specific name for the maplibre-gl Map type.

-import type { Map } from 'maplibre-gl';
+import type { Map as MapLibreMap } from 'maplibre-gl';
🧰 Tools
🪛 Biome

[error] 3-3: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss (1)

63-81: LGTM! Consider adding a comment explaining the !important flags.

The changes correctly implement container-based map sizing, ensuring the map properly fills its container. The use of position: relative and overflow: hidden provides proper positioning context and prevents unwanted scrollbars.

Consider adding a brief comment explaining why !important flags are necessary (to override maplibregl's inline styles).

src/features/projectsV2/ProjectsMap/MultipleProjectsView.tsx (2)

7-7: Good architectural improvement moving to context-based state management!

The transition from prop-based to context-based state management for map view state is a positive change that:

  • Reduces prop drilling
  • Centralizes map state management
  • Makes the component more focused on its core responsibilities

Also applies to: 11-14


Line range hint 39-64: Optimize useMemo dependencies.

The memoization implementation is good, but the dependency array includes unnecessary items. isLoading and isError don't affect the categorization logic and can be removed from the dependencies.

   }, [projects, filteredProjects, isLoading, isError]);
+  }, [projects, filteredProjects]);
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss (1)

3-4: LGTM! Consider adding documentation for layout variables.

The introduction of layout padding variables improves maintainability. Consider adding a brief comment explaining their purpose and relationship with other layout components.

+// Base padding values for project layout components
 $layoutPaddingTop: 24px;
 $layoutPaddingSide: 20px;
src/features/projectsV2/ProjectsMapContext.tsx (2)

29-37: Consider adding runtime validation for width/height values.

While setting default dimensions to '100%' is good, consider adding runtime validation to ensure these critical dimensions are never undefined or invalid, which could break the map rendering.

const validateViewState = (state: ExtendedViewState): ExtendedViewState => {
  return {
    ...state,
    width: state.width ?? '100%',
    height: state.height ?? '100%'
  };
};

107-111: Consider enhancing type safety for context value.

While the context structure is clean, consider using a non-null assertion or proper type guard to ensure type safety of the context value.

const value = useMemo(
  (): ProjectsMapState => ({
    mapState,
    viewState,
    handleViewStateChange,
    isSatelliteView,
    setIsSatelliteView,
    mapOptions,
    updateMapOption,
  }),
  [mapState, viewState, mapOptions, isSatelliteView]
);
src/features/projectsV2/ProjectsMap/SingleProjectView.tsx (3)

51-57: Consider optimizing zoom duration for better UX.

While the function calls are correctly updated, the zoom duration of 4000ms (4 seconds) might feel slow to users. Consider reducing this value to 2000-2500ms for a snappier experience while still maintaining smooth animation.

-        handleViewStateChange,
-        4000
+        handleViewStateChange,
+        2500

70-71: Maintain consistent zoom duration across the component.

For consistency with the earlier suggestion, consider updating this zoom duration as well.

         handleViewStateChange,
-        4000
+        2500

Line range hint 39-60: Add cleanup functions to useEffect hooks.

The zoom effects should clean up their animations when the component unmounts or dependencies change. This prevents potential race conditions with concurrent animations.

   useEffect(() => {
+    let isActive = true;
     if (!router.isReady || selectedPlantLocation === null) return;
     
     // ... existing zoom logic ...
+    
+    return () => {
+      isActive = false;
+      mapRef.current?.stop(); // Stop any ongoing animations
+    };
   }, [selectedPlantLocation, router.isReady]);

   useEffect(() => {
+    let isActive = true;
     if (!router.isReady || selectedPlantLocation !== null) return;
     
     // ... existing zoom logic ...
+    
+    return () => {
+      isActive = false;
+      mapRef.current?.stop(); // Stop any ongoing animations
+    };
   }, [selectedSite, sitesGeojson, router.isReady, selectedPlantLocation]);

Also applies to: 63-87

src/features/projectsV2/ProjectDetails/components/KeyInfo.tsx (1)

52-114: Clean and well-organized conditional rendering!

The restructured conditional blocks effectively group related information and leverage the visibility flags for cleaner JSX. The implementation successfully simplifies the conditional rendering as intended.

Consider extracting the repeated styles.keyInfoSubContainer div pattern into a reusable component for even better maintainability.

+const KeyInfoSection: React.FC<{ show: boolean; children: React.ReactNode }> = ({
+  show,
+  children,
+}) => {
+  if (!show) return null;
+  return <div className={styles.keyInfoSubContainer}>{children}</div>;
+};

 const KeyInfo = ({...}) => {
   // ...
   return (
     <div className={styles.keyInfoContainer}>
-      {(showAbandonmentInfo ||
-        restorationDate.length > 0 ||
-        showProtectionStarted) && (
-        <div className={styles.keyInfoSubContainer}>
+      <KeyInfoSection
+        show={
+          showAbandonmentInfo ||
+          restorationDate.length > 0 ||
+          showProtectionStarted
+        }
+      >
           {/* ... */}
-        </div>
-      )}
+      </KeyInfoSection>
src/features/projectsV2/ProjectsMap/index.tsx (1)

57-76: Consider extracting magic number as a named constant

The debounced map centering logic with the 30 projects threshold is a good solution to prevent unnecessary re-centering. However, the magic number 30 should be extracted as a named constant for better maintainability.

+const MAX_PROJECTS_FOR_AUTO_CENTER = 30;
+
 useDebouncedEffect(
   () => {
     const shouldCenterMap =
       filteredProjects !== undefined &&
       filteredProjects.length > 0 &&
-      filteredProjects.length < 30 &&
+      filteredProjects.length < MAX_PROJECTS_FOR_AUTO_CENTER &&
       mapRef.current;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 355e02b and 5f060ac.

⛔ Files ignored due to path filters (1)
  • package.json is excluded by !**/*.json
📒 Files selected for processing (14)
  • .gitignore (1 hunks)
  • src/features/common/Layout/ProjectsLayout/ProjectsLayout.module.scss (1 hunks)
  • src/features/projectsV2/ProjectDetails/ProjectDetails.module.scss (1 hunks)
  • src/features/projectsV2/ProjectDetails/components/KeyInfo.tsx (1 hunks)
  • src/features/projectsV2/ProjectsMap/MultipleProjectsView.tsx (3 hunks)
  • src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss (2 hunks)
  • src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss (1 hunks)
  • src/features/projectsV2/ProjectsMap/SingleProjectView.tsx (3 hunks)
  • src/features/projectsV2/ProjectsMap/index.tsx (6 hunks)
  • src/features/projectsV2/ProjectsMapContext.tsx (5 hunks)
  • src/utils/countryCurrency/getFormattedDate.ts (1 hunks)
  • src/utils/mapsV2/zoomToLocation.tsx (2 hunks)
  • src/utils/mapsV2/zoomToPolygonPlantLocation.tsx (2 hunks)
  • src/utils/mapsV2/zoomToProjectSite.ts (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 Biome
src/utils/mapsV2/zoomToProjectSite.ts

[error] 3-3: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🔇 Additional comments (24)
src/features/projectsV2/ProjectDetails/ProjectDetails.module.scss (1)

5-6: LGTM! Improved content visibility with better spacing.

The height calculation and padding changes work together effectively to:

  1. Extend the container height by 30px
  2. Add matching bottom padding to prevent content from touching the container edge
  3. Maintain scrollability while improving content visibility

This aligns well with the PR objective to allow project details to overflow to the bottom of the page.

src/utils/mapsV2/zoomToLocation.tsx (2)

1-2: LGTM! Type imports and parameter signature changes improve type safety.

The changes to use explicit type imports and the more flexible Partial<ViewState> parameter type are good improvements. This aligns with TypeScript best practices and allows for more granular state updates.

Also applies to: 5-5


Line range hint 1-37: Verify the impact on map re-centering behavior.

Given the PR objectives mention fixing map re-centering issues with filtered projects, let's verify how this function interacts with the project filtering logic.

✅ Verification successful

Let me try a different search strategy to understand the usage of this function and its interaction with filtering logic.


Let me try one more search with modified file extensions to get the actual usage context:


Based on the search results, I can now provide a final response:

Map re-centering behavior is properly integrated with project filtering

The code shows that the zoomToLocation function is correctly integrated with the project filtering system:

  • In ProjectsMap/index.tsx, there's a dedicated logic to handle map centering when filtered projects change:
    const shouldCenterMap =
      filteredProjects !== undefined &&
      filteredProjects.length > 0 &&
      filteredProjects.length < 30;
  • The function properly updates the view state through handleViewStateChange callback, which is consistently used across both single and multiple project views
  • The implementation includes proper duration and zoom level controls for smooth transitions

The changes to zoomToLocation function maintain compatibility with both filtered and unfiltered project views, ensuring consistent map behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for references to zoomToLocation in filter-related code
echo "Searching for filter-related code that uses zoomToLocation..."
rg -l "zoomToLocation.*filter" --type ts --type tsx

# Search for any state management code related to map centering
echo "Searching for map center state management..."
ast-grep --pattern 'const [$_] = useState<$_>({ latitude: $_, longitude: $_ })'

Length of output: 395


Script:

#!/bin/bash
# Search for all usages of zoomToLocation function
echo "Searching for all imports and usages of zoomToLocation..."
rg "zoomToLocation" -A 3 --type ts --type typescript --type tsx

# Search for files containing both map filtering and viewport/view state changes
echo "Searching for files with map filtering and view state..."
rg "filter.*projects?" --type ts --type typescript --type tsx -l | xargs rg "ViewState|viewState|handleViewStateChange" -l

# Look for map ref usage with filtering
echo "Searching for mapRef usage with filtering..."
rg "mapRef.*filter|filter.*mapRef" -A 3 --type ts --type typescript --type tsx

Length of output: 1553


Script:

#!/bin/bash
# Search for direct usages of zoomToLocation
echo "Searching for zoomToLocation usage..."
rg "zoomToLocation" -B 2 -A 5 src/

# Look for the filtering logic in map components
echo "Searching for filtering logic in ProjectsMap components..."
rg "filter" -B 2 -A 5 src/features/projectsV2/ProjectsMap/

# Check for viewState handling in map components
echo "Checking viewState handling..."
rg "handleViewStateChange" -B 2 -A 5 src/features/projectsV2/ProjectsMap/

Length of output: 23808

src/utils/countryCurrency/getFormattedDate.ts (1)

6-8: LGTM! Good defensive programming practice.

The early return for falsy values prevents unnecessary processing and provides consistent behavior.

src/utils/mapsV2/zoomToPolygonPlantLocation.tsx (2)

1-4: LGTM! Clean import organization.

The consolidation and separation of type imports improve code organization and readability.


8-11: LGTM! Improved state management approach.

The transition from setViewState to handleViewStateChange with Partial<ViewState> aligns well with the context-based state management pattern, offering more flexibility while maintaining type safety.

src/features/common/Layout/ProjectsLayout/ProjectsLayout.module.scss (1)

52-52: LGTM! Verify layout across different screen sizes.

The 2px increase in top spacing aligns with the PR objectives to improve positioning of map controls. However, since this change affects all screen sizes, not just mobile views, please verify that the layout remains consistent across different viewport dimensions.

Let's verify the impact on different screen sizes:

✅ Verification successful

Based on the search results, I can now make a determination about the review comment. The search revealed:

  1. The .mapFeatureExplorerOverlay class in ProjectsLayout.module.scss is positioned absolutely with the modified top position
  2. The codebase has extensive responsive design patterns using mixins for different screen sizes (xs, sm, md, lg, xl)
  3. No direct conflicts or dependencies were found for this specific overlay positioning
  4. The change appears to be isolated to this specific component's styling

LGTM - The 2px spacing adjustment is safe and maintains responsive layout

The increased top spacing from 8px to 10px is a minor adjustment that:

  • Maintains the consistent use of the $layoutPaddingTop variable
  • Doesn't interfere with any media queries or responsive breakpoints
  • Is applied uniformly across all screen sizes as intended
  • Aligns with the PR's goal of improving map control positioning
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any responsive design breakpoints or screen-size specific styles that might be affected by this change

# Test 1: Look for responsive breakpoints in SCSS files
echo "Checking for responsive breakpoints that might affect the overlay positioning..."
rg -A 2 "@include.*\b(xs|sm|md|lg|xl)" --type scss

# Test 2: Search for related mobile-specific styles
echo "Checking for mobile-specific styles related to map controls..."
rg -A 5 "mapFeatureExplorerOverlay|zoom.*button|map.*control" --type scss

Length of output: 492


Script:

#!/bin/bash
# Let's try searching without file type restriction since scss is not recognized
# First, find all scss files
echo "Finding SCSS files..."
fd ".*\.scss$"

# Then search for responsive breakpoints and map-related styles
echo -e "\nChecking for responsive breakpoints..."
rg -A 2 "@include.*\b(xs|sm|md|lg|xl)" $(fd ".*\.scss$")

echo -e "\nChecking for map-related styles..."
rg -A 5 "mapFeatureExplorerOverlay|zoom.*button|map.*control" $(fd ".*\.scss$")

# Also check for any media queries that might affect the layout
echo -e "\nChecking for media queries..."
rg "@media" $(fd ".*\.scss$")

Length of output: 149094

src/utils/mapsV2/zoomToProjectSite.ts (2)

24-24: LGTM! Improved function signature.

The renamed parameter and updated type signature better reflect the function's purpose and provide more flexibility with Partial<ViewState>.


68-68: LGTM! Verify context integration.

The view state update is correctly implemented. Since this is part of a larger transition to context-based state management, let's verify the integration.

✅ Verification successful

Let me gather more specific information about the view state management integration.


View state management integration is properly implemented

The verification confirms that:

  • The handleViewStateChange callback is correctly integrated with the context-based state management in ProjectsMapContext
  • SingleProjectView properly consumes the context through the useProjectsMap hook
  • The view state updates are consistently handled across zoom operations (project sites, locations, and coordinates)
  • The state management follows the context pattern with appropriate typing and default values

The implementation maintains a clean separation of concerns while ensuring proper state synchronization through the context system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of handleViewStateChange across the codebase
# to ensure consistent context-based state management.

# Search for components using this utility function
echo "Components using zoomInToProjectSite:"
rg -l "zoomInToProjectSite"

# Check the implementation of handleViewStateChange in these components
echo "\nContext usage in components:"
ast-grep --pattern 'const $_ = useContext($_)'

Length of output: 6174


Script:

#!/bin/bash
# Check the implementation details in the relevant files

# Check SingleProjectView implementation
echo "SingleProjectView implementation:"
rg -A 10 "handleViewStateChange" src/features/projectsV2/ProjectsMap/SingleProjectView.tsx

# Check for map context usage
echo "\nMap context usage in SingleProjectView:"
ast-grep --pattern 'const $_ = useContext(ProjectsMapContext)' src/features/projectsV2/ProjectsMap/SingleProjectView.tsx

# Check ProjectsMapContext implementation
echo "\nProjectsMapContext view state handling:"
rg -A 5 "viewState" src/features/projectsV2/ProjectsMapContext.tsx

Length of output: 2687

src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss (2)

85-85: LGTM! Fixes zoom button visibility on Android.

The increased bottom spacing prevents the zoom controls from being obscured by the footer on Android devices.


89-89: LGTM! Optimizes zoom button positioning for iOS.

The reduced bottom spacing provides better balance while maintaining visibility of the zoom controls on iOS devices.

src/features/projectsV2/ProjectsMap/MultipleProjectsView.tsx (3)

16-18: Clean implementation of context consumption!

The component properly consumes both contexts (useProjects and useProjectsMap) with clean destructuring patterns while maintaining proper error handling.


Line range hint 66-69: Clean and focused render logic!

The component maintains a clean and focused render method, passing only the necessary props to ProjectMarkers.


Line range hint 24-37: Consider handling potential race conditions and effect dependencies.

While the deferred execution pattern is good for ensuring map initialization, there are two concerns:

  1. Race Condition: Multiple effect executions could lead to race conditions in map initialization. Consider adding a cleanup function to cancel pending operations.
  2. Dependencies: The empty dependency array might miss necessary updates. Consider including handleViewStateChange and mapRef as dependencies.

Consider applying this improvement:

-  useEffect(() => {
+  useEffect(() => {
+    let isMounted = true;
     Promise.resolve().then(() => {
-      if (mapRef.current) {
+      if (isMounted && mapRef.current) {
         const map = mapRef.current.getMap
           ? mapRef.current.getMap()
           : mapRef.current;
         zoomOutMap(map, () => {
           handleViewStateChange({
             ...map.getCenter(),
             zoom: map.getZoom(),
           });
         });
       }
     });
+    return () => {
+      isMounted = false;
+    };
-  }, []);
+  }, [handleViewStateChange, mapRef]);
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss (1)

18-19: LGTM! Improved dropdown positioning.

The transition from hardcoded values to calculated positions using layout variables enhances consistency and maintainability. The additional 10px offset provides appropriate visual spacing.

src/features/projectsV2/ProjectsMapContext.tsx (2)

9-13: LGTM! Well-designed interface extension.

The ExtendedViewState interface appropriately extends ViewState with flexible width/height types, supporting both percentage and pixel values. This change aligns with the PR objective of improving map container responsiveness.


77-84: 🛠️ Refactor suggestion

Review the forced dimension override approach.

The current implementation always forces width/height to '100%', which might prevent legitimate dimension changes needed for responsive layouts or specific container requirements.

Consider a more flexible approach:

 const handleViewStateChange = (newViewState: Partial<ExtendedViewState>) => {
   setViewState((prev) => ({
     ...prev,
     ...newViewState,
-    width: '100%', // Always ensure width and height are set
-    height: '100%',
+    width: newViewState.width ?? prev.width ?? '100%',
+    height: newViewState.height ?? prev.height ?? '100%',
   }));
 };
src/features/projectsV2/ProjectsMap/SingleProjectView.tsx (1)

24-24: Good rename to better reflect the function's purpose!

The change from setViewState to handleViewStateChange better describes the function's intent and follows React's event handling naming conventions.

src/features/projectsV2/ProjectDetails/components/KeyInfo.tsx (3)

38-47: Well-structured visibility flags improve code maintainability!

The introduction of clear, descriptive boolean flags at the top of the component effectively centralizes the visibility logic and makes the code more maintainable. Each flag properly handles null checks and ensures meaningful values.


Line range hint 124-134: Consistent implementation of seasons rendering!

The code effectively reuses the InterventionSeason component for both activity and planting seasons, maintaining consistency with the visibility flag pattern established above.


48-48: Verify date formatting implementation.

The code now uses the formatDate utility instead of a local implementation. Let's verify that this utility handles the required string cleanup and zero-padding mentioned in the PR objectives.

✅ Verification successful

Let me check the implementation of the formatDate utility to verify it handles the required formatting.


Let me see the complete implementation to verify the zero-padding and formatting logic.


Date formatting implementation is properly handled

The formatDate utility correctly implements the required functionality:

  • Cleans up date strings by removing time portion
  • Handles zero-padding for month and day using padStart(2, '0')
  • Uses date-fns for consistent formatting with localization support
  • Returns dates in the format "Month DD, YYYY"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the formatDate utility implementation
rg -l "function.*formatDate" src/utils/

Length of output: 87


Script:

#!/bin/bash
# Get the implementation of formatDate
rg -A 10 "function.*formatDate" src/utils/countryCurrency/getFormattedDate.ts

Length of output: 435


Script:

#!/bin/bash
# Get the complete implementation of formatDate
cat src/utils/countryCurrency/getFormattedDate.ts

Length of output: 1028

src/features/projectsV2/ProjectsMap/index.tsx (3)

1-1: LGTM: Import changes enhance type safety and performance

The addition of ViewStateChangeEvent type and useDebouncedEffect hook are good improvements for type safety and performance optimization.

Also applies to: 25-25


42-43: LGTM: Improved view state management

The transition from direct state setting to a handled approach with handleViewStateChange is a good improvement. The onMove callback is properly memoized and typed.

Also applies to: 105-110


Line range hint 181-189: Consider dynamic navigation control positioning for mobile devices

The fixed bottom-right position for navigation controls might still cause issues on mobile devices. Consider adjusting the position dynamically based on the device type to prevent the controls from being obscured by the footer.

-<NavigationControl position="bottom-right" showCompass={false} />
+<NavigationControl
+  position={props.isMobile ? "bottom-left" : "bottom-right"}
+  showCompass={false}
+/>

- also debounces the useEffect that runs on updates to `filteredProjects` to prevent excessive map centering
- adds a check to prevent map centering if position won't significantly 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

🧹 Outside diff range and nitpick comments (3)
src/features/projectsV2/ProjectsMap/index.tsx (2)

9-9: Consider addressing the Map component shadowing.

The Map import shadows the global Map object. While this is common practice with mapping libraries, it's better to be explicit.

Consider renaming to:

-import Map from 'react-map-gl-v7/maplibre';
+import MapGL from 'react-map-gl-v7/maplibre';
🧰 Tools
🪛 Biome

[error] 9-9: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)


58-83: Consider extracting complex conditions for better readability.

The map centering logic is well-implemented with proper checks and debouncing. However, the complex conditions could be more readable.

Consider this refactor:

  useDebouncedEffect(
    () => {
      const map = mapRef.current;
+     const isValidProjectCount =
+       filteredProjects !== undefined &&
+       filteredProjects.length > 0 &&
+       (filteredProjects.length < 30 || filteredProjects.length === projects?.length);
+
-     const shouldCenterMap =
-       filteredProjects !== undefined &&
-       filteredProjects.length > 0 &&
-       (filteredProjects.length < 30 ||
-         filteredProjects.length === projects?.length) &&
-       map !== null;
+     const shouldCenterMap = isValidProjectCount && map !== null;
      if (!shouldCenterMap) return;

      const validFeatures = getValidFeatures(filteredProjects);
      if (validFeatures.length === 0) return;

      const centroid = calculateCentroid(validFeatures);
      if (!centroid.geometry) return;

      const currentCenter = map.getCenter();
      if (areMapCoordsEqual(currentCenter, centroid.geometry.coordinates))
        return;

      centerMapOnCoordinates(mapRef, centroid.geometry.coordinates);
    },
    250,
    [filteredProjects]
  );
src/utils/projectV2.ts (1)

224-242: LGTM! Consider extracting the epsilon constant.

The implementation is clean, well-documented, and serves its purpose in preventing unnecessary map re-centering. However, consider extracting the epsilon constant to improve maintainability.

+// Distance threshold in degrees (approximately 10 meters at the Equator)
+const MAP_COORDS_EPSILON = 0.00009;
+
 export const areMapCoordsEqual = (
   mapCenter: { lng: number; lat: number } | undefined,
   centroidCoords: Position,
-  epsilon = 0.00009 // Very small difference threshold corresponding to 10m at Equator
+  epsilon = MAP_COORDS_EPSILON
 ): boolean => {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5f060ac and a07e8d5.

⛔ Files ignored due to path filters (1)
  • package.json is excluded by !**/*.json
📒 Files selected for processing (3)
  • .gitignore (1 hunks)
  • src/features/projectsV2/ProjectsMap/index.tsx (6 hunks)
  • src/utils/projectV2.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
🧰 Additional context used
🪛 Biome
src/features/projectsV2/ProjectsMap/index.tsx

[error] 9-9: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🔇 Additional comments (4)
src/features/projectsV2/ProjectsMap/index.tsx (3)

43-44: LGTM! Improved state management approach.

The transition from direct state setting to a handled approach provides better control over view state updates.


112-117: LGTM! Well-structured event handler.

The onMove handler is properly memoized and uses the new handleViewStateChange approach consistently.


188-188: LGTM! Consistent event handling.

The Map component's onMove prop correctly uses the new callback.

src/utils/projectV2.ts (1)

224-242: Verify the function's usage in map-related components.

Let's verify that this function is being used correctly in the components that handle map centering and filtering.

✅ Verification successful

Function is correctly used for map centering logic

The verification shows that areMapCoordsEqual is properly implemented and used in the ProjectsMap component to prevent unnecessary re-centering of the map. It compares the current map center with centroid coordinates before triggering the centering operation, which is an appropriate optimization.

  • Used in src/features/projectsV2/ProjectsMap/index.tsx as part of a debounced map centering logic
  • No other coordinate comparison functions exist in the utils that could cause conflicts
  • Implementation follows best practices for coordinate comparison with epsilon threshold
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find components that use areMapCoordsEqual for map centering logic

# Test 1: Find direct usage of areMapCoordsEqual
echo "=== Direct usage of areMapCoordsEqual ==="
rg "areMapCoordsEqual" --type ts --type tsx -l

# Test 2: Find components that might need this function
echo -e "\n=== Components handling map center or filtering ==="
rg -A 5 "setViewState|handleViewStateChange" --type tsx

Length of output: 372


Script:

#!/bin/bash
# Let's try without file type restrictions since tsx might not be recognized
# Find direct usage of areMapCoordsEqual
echo "=== Direct usage of areMapCoordsEqual ==="
rg "areMapCoordsEqual" -l

# Find components handling map view state
echo -e "\n=== Components handling map view state ==="
rg -l "(setViewState|handleViewStateChange|mapCenter)"

# Look for map-related components
echo -e "\n=== Map-related components ==="
fd -e tsx -e ts "Map" 

Length of output: 2411


Script:

#!/bin/bash
# Let's examine how areMapCoordsEqual is used in ProjectsMap component
echo "=== Usage in ProjectsMap ==="
rg -A 10 "areMapCoordsEqual" src/features/projectsV2/ProjectsMap/index.tsx

# Let's also check the context of map center handling
echo -e "\n=== Map center handling context ==="
rg -B 5 -A 10 "mapCenter" src/features/projectsV2/ProjectsMap/index.tsx

# Check if there are any other coordinate comparison functions
echo -e "\n=== Other coordinate comparison functions ==="
rg "(isEqual|compare|equals.*coord)" src/utils/

Length of output: 1663

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

🧹 Outside diff range and nitpick comments (5)
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/ProjectSiteList.tsx (1)

52-54: Consider enhancing the area formatting for better internationalization and precision.

While the locale-aware formatting is a good improvement, consider these enhancements:

  1. Internationalize the "ha" unit using the translation system
  2. Consider showing decimals for small areas (< 1 ha)
  3. Extract the formatting logic to a separate function for better maintainability
-            <p className={styles.siteArea}>
-              {getFormattedRoundedNumber(locale, site.siteArea, 0)} ha
-            </p>
+            <p className={styles.siteArea}>
+              {formatSiteArea(locale, site.siteArea)}
+            </p>

+ // Add this function above the component
+ const formatSiteArea = (locale: string, area: number) => {
+   const decimals = area < 1 ? 2 : 0;
+   const formattedArea = getFormattedRoundedNumber(locale, area, decimals);
+   // Assuming you have a translation function like t()
+   const unit = t('common.units.hectare');
+   return `${formattedArea} ${unit}`;
+ };
src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss (1)

180-183: LGTM! Consider consolidating scientific name styles.

The addition of italic styling for scientific names follows proper typographic conventions.

Consider consolidating all scientific name styles into a single shared class to maintain consistency, as there are multiple instances of scientific name styling in this file (e.g., .scientificName on line 139). Here's a suggested approach:

- .scientificName .data {
-   font-style: italic;
- }
+ @mixin scientific-name {
+   font-style: italic;
+ }
+
+ .scientificName .data {
+   @include scientific-name;
+ }

Then update other scientific name styles to use this mixin for consistency.

src/features/projectsV2/ProjectDetails/components/microComponents/PlantInfoCard.tsx (1)

Line range hint 41-43: Fix incorrect logical condition in shouldRender

The current condition tag !== undefined || tag !== null will always evaluate to true because any value will either be different from undefined OR different from null. This means the tag will always render, even when it shouldn't.

Apply this fix:

    {
      label: tProjectDetails('treeTag'),
      data: tProjectDetails('tag', {
        number: tag,
      }),
-     shouldRender: tag !== undefined || tag !== null,
+     shouldRender: tag !== undefined && tag !== null,
    },
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx (2)

98-105: Add error handling and consider configuration for decimal places

While the formatting implementation is good, consider these improvements:

  1. Add null/undefined checking for siteArea
  2. Consider making decimal places configurable based on the area size

Consider this safer implementation:

-                    <span>
-                      {getFormattedRoundedNumber(
-                        locale,
-                        selectedSiteData?.siteArea,
-                        0
-                      )}{' '}
-                      ha
-                    </span>
+                    <span>
+                      {selectedSiteData?.siteArea
+                        ? `${getFormattedRoundedNumber(
+                            locale,
+                            selectedSiteData.siteArea,
+                            selectedSiteData.siteArea < 1 ? 2 : 0
+                          )} ha`
+                        : '-'}
+                    </span>

Line range hint 42-135: Consider component decomposition for better maintainability

While the current implementation works well, consider these architectural improvements for future iterations:

  1. Extract the site area display into a separate component
  2. Consider using a custom hook for site selection logic
  3. Move dropdown state management to a context if it needs to be shared

This would improve maintainability and make the component more focused on its primary responsibility.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a07e8d5 and a6ed9e2.

📒 Files selected for processing (4)
  • src/features/projectsV2/ProjectDetails/components/microComponents/PlantInfoCard.tsx (1 hunks)
  • src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss (1 hunks)
  • src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/ProjectSiteList.tsx (3 hunks)
  • src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx (4 hunks)
🔇 Additional comments (6)
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/ProjectSiteList.tsx (2)

1-2: LGTM! Imports are correctly added for locale support.

The new imports support the enhancement of number formatting with locale awareness.


32-32: LGTM! Locale initialization is properly implemented.

The useLocale hook is correctly used at the component level for locale-aware formatting.

src/features/projectsV2/ProjectDetails/components/microComponents/PlantInfoCard.tsx (2)

60-62: LGTM: Styling enhancement for scientific names

The addition of the styles.scientificName class improves the visual distinction of scientific names.


Line range hint 1-96: Consider enhancing error handling for date formatting

The component uses formatDate utility without error handling. While the date is checked for existence, invalid date strings could cause runtime errors.

Let's check the implementation of formatDate:

Consider wrapping the date formatting in a try-catch block:

    {
      label: tProjectDetails('plantingDate'),
-     data: interventionStartDate ? formatDate(interventionStartDate) : null,
+     data: interventionStartDate ? 
+       (() => {
+         try {
+           return formatDate(interventionStartDate);
+         } catch (error) {
+           console.error('Error formatting date:', error);
+           return null;
+         }
+       })() 
+       : null,
      shouldRender: interventionStartDate !== undefined,
    },
src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx (2)

9-9: LGTM: Import additions for localization support

The new imports support the enhancement of number formatting with locale-specific handling.

Also applies to: 18-18


56-56: LGTM: Proper locale hook initialization

The useLocale hook is correctly initialized at the component level for consistent locale-based formatting.

Copy link
Contributor

@mariahosfeld mariahosfeld left a comment

Choose a reason for hiding this comment

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

Two points:

  • the separator also needs to be applied on the list of planted species, we can have 4 digits here as well
    image
  • with the applied fix, the zoom out control is now totally overlapped by the footer on my mobile
    image

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

🧹 Outside diff range and nitpick comments (1)
src/features/projectsV2/ProjectDetails/components/microComponents/SpeciesPlanted.tsx (1)

38-38: Consider adding defensive checks for edge cases.

While the number formatting implementation is good, consider handling edge cases for better robustness.

-              <p>{getFormattedNumber(locale, species.treeCount)}</p>
+              <p>{species.treeCount != null ? getFormattedNumber(locale, species.treeCount) : '-'}</p>

This change ensures graceful handling of potential null or undefined values.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2492c34 and 2698608.

📒 Files selected for processing (2)
  • src/features/projectsV2/ProjectDetails/components/microComponents/SpeciesPlanted.tsx (3 hunks)
  • src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss
🔇 Additional comments (3)
src/features/projectsV2/ProjectDetails/components/microComponents/SpeciesPlanted.tsx (3)

5-6: LGTM! Import statements are properly structured.

The new imports for locale handling and number formatting align well with the PR's objective to enhance data presentation.


15-15: LGTM! Proper hook usage for locale initialization.

The locale initialization is correctly placed and follows React hooks best practices.


Line range hint 1-47: Verify consistent number formatting across the application.

The number formatting changes look good, but we should ensure consistency across other components that display numbers.

✅ Verification successful

Number formatting is consistently implemented across the application

Based on the search results, the getFormattedNumber utility is already widely used across the application for number formatting, including:

  • Tree counts in leaderboards
  • Project statistics and metrics
  • Analytics components
  • Plant location details
  • Species counts and percentages

The implementation in SpeciesPlanted.tsx follows the established pattern of using getFormattedNumber for displaying numeric values, consistent with other components in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for direct number rendering in other components
# Look for potential places where getFormattedNumber should be used

# Search for components that might need similar formatting
rg -t tsx -t jsx "{\s*[a-zA-Z]*Count\s*}" --glob "src/features/**"

# Search for other numeric displays that might need formatting
rg -t tsx -t jsx "toFixed|toString|Number\." --glob "src/features/**"

Length of output: 266


Script:

#!/bin/bash
# Search for components that might need similar formatting
rg "\\{\\s*\\w+Count\\s*\\}" --type=ts --type=tsx src/features/

# Search for other numeric displays that might need formatting
rg "toFixed\\(|toString\\(|Number\\." --type=ts --type=tsx src/features/

# Search for existing usage of getFormattedNumber
rg "getFormattedNumber" --type=ts --type=tsx

Length of output: 261


Script:

#!/bin/bash
# Search for components that might need similar formatting
rg "\\{\\s*\\w+Count\\s*\\}" 

# Search for other numeric displays that might need formatting
rg "toFixed\\(|toString\\(|Number\\."

# Search for existing usage of getFormattedNumber
rg "getFormattedNumber"

Length of output: 23876

@mariahosfeld mariahosfeld self-requested a review November 11, 2024 09:40
Copy link
Contributor

@mariahosfeld mariahosfeld left a comment

Choose a reason for hiding this comment

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

All functionalities work for me now.

Copy link
Contributor

@sunilsabatp sunilsabatp left a comment

Choose a reason for hiding this comment

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

LGTM

@mohitb35 mohitb35 merged commit 4080b6b into develop Nov 12, 2024
8 of 9 checks passed
@mohitb35 mohitb35 deleted the projects-redesign/launch-feedback branch November 12, 2024 06:54
@coderabbitai coderabbitai bot mentioned this pull request Jan 13, 2025
3 tasks
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.

3 participants