-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/intervention #2343
base: develop
Are you sure you want to change the base?
Feature/intervention #2343
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
53257dc
to
43d3856
Compare
5fb466c
to
9f9021c
Compare
Is the intervention feature applicable to all projects or only to selected ones? The interaction with the intervention dropdown does not show any results for some projects. Could you hide the intervention dropdown or its options if it is not applicable to a project? |
It's should be visible for all Project. Not sure whether we would require to hide it when no intervention is present. |
This comment was marked as resolved.
This comment was marked as resolved.
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 eslint
npm warn config production Use WalkthroughThis pull request introduces significant enhancements to the project's intervention management system, focusing on the user interface and functionality for displaying and interacting with various plant locations and interventions. Key changes include the addition of new React components, modifications to type definitions, the implementation of dropdown menus for intervention selection, and styling updates to support detailed intervention information across the project's map and details views. Changes
Sequence DiagramsequenceDiagram
participant User
participant MapControls
participant InterventionDropdown
participant ProjectsContext
participant ProjectsMap
User->>MapControls: Open intervention dropdown
MapControls->>InterventionDropdown: Render dropdown
User->>InterventionDropdown: Select intervention type
InterventionDropdown->>ProjectsContext: Update selectedIntervention
ProjectsContext-->>ProjectsMap: Filter plant locations
ProjectsMap->>User: Display filtered locations
Possibly related PRs
Suggested Labels
Suggested Reviewers
Poem
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
🧹 Nitpick comments (19)
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx (1)
9-9
: Remove or rename unusedtype
prop.According to the static analysis hint,
type
is not utilized in this component. If it's truly irrelevant, remove it from both the component signature and theProps
interface; otherwise, prefix it with an underscore if you intend to keep it as an unused placeholder.-const OtherInterventionInfoHeader = ({ plantDate, type }: Props) => { +const OtherInterventionInfoHeader = ({ plantDate }: Props) => {🧰 Tools
🪛 GitHub Check: CodeFactor
[notice] 9-9: src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx#L9
'type' is defined but never used. Allowed unused args must match /^_/u. (@typescript-eslint/no-unused-vars)src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx (1)
14-17
: Provide a fallback label for missing intervention data.When an intervention is not found in
AllIntervention
, returning an empty string may lead to unclear UI states. Consider using a more descriptive fallback label (e.g., "Unknown Intervention") to help users understand the missing data.return found ? found.label : ''; +// Or use a fallback: +// return found ? found.label : 'Unknown Intervention';src/utils/mapsV2/zoomOut.tsx (1)
17-17
: MakenewZoom
configurable.Locking the zoom level to
12
may not be ideal for all user flows and map contexts. Allowing it to be set via a parameter or context would improve adaptability.const newZoom = 12; +// Consider passing zoom as a parameter: +// function zoomOut(handleViewStateChange, mapRef, { duration = 1000, zoom = 12 }) { +// ... +// const newZoom = zoom;Also applies to: 19-24
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx (1)
32-60
: Consider splitting nested logic into separate helper functions.
Multiple nested conditions make the code harder to follow. Splitting out the JSON parsing and key/value processing into smaller functions will improve readability and maintainability.- if (typeof value === 'string') { - checkForPublic.push({ value, key }); - } else if (typeof value === 'object' && value !== null && 'value' in value && 'label' in value) { - if (isJsonString(value.value)) { - ... - } - ... - } + function parsePublicEntry(key: string, value: string | MetaDataValue) { + if (typeof value === 'string') { + return { key, value }; + } + if (typeof value === 'object' && value !== null && 'value' in value && 'label' in value) { + if (isJsonString(value.value)) { + // parse JSON if valid + } + return { key: value.label, value: value.value }; + } + return null; + } + + // then call parsePublicEntry within forEachsrc/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx (1)
63-73
: Remove unnecessary fragment.
According to the static analysis tool, the fragment containing a single child is redundant. Removing it simplifies the JSX.- <> {selectedSiteData && ( <div className={styles.labelTextContainer}> ... </div> )} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 63-73: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/utils/constants/intervention.ts (1)
48-88
: Consider localization of labels
TheAllIntervention
array contains user-facing labels. If the application supports multiple languages, consider integrating these text values into your translation system to maintain consistency.src/features/projectsV2/ProjectsMap/MapControls.tsx (1)
78-79
: Confirm role ofdisableInterventionFilter
Closely review how this prop is used. If it also merely callssetDisableInterventionMenu(false)
, consider inlining it to simplify logic.src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (3)
50-65
: Leverage optional chaining to simplify
You can avoid nested property checks by using optional chaining.- plantLocationInfo && - plantLocationInfo.plantedSpecies && - plantLocationInfo.plantedSpecies.length > 0 + plantLocationInfo?.plantedSpecies?.length > 0🧰 Tools
🪛 Biome (1.9.4)
[error] 52-53: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
68-78
: Optional chain for sampleInterventions
Consider usingplantLocationInfo?.sampleInterventions?.map
to streamline the check and reduce potential undefined errors.-if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { - const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { +if (plantLocationInfo?.sampleInterventions?.length > 0) { + const result = plantLocationInfo.sampleInterventions.map((item) => {🧰 Tools
🪛 Biome (1.9.4)
[error] 69-75: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
116-117
: Optional chain for sampleInterventions
Similarly, you can apply an optional chain when accessingplantLocationInfo.sampleInterventions
.- plantLocationInfo && - plantLocationInfo.sampleInterventions && - plantLocationInfo.sampleInterventions.length > 0 + plantLocationInfo?.sampleInterventions?.length > 0🧰 Tools
🪛 Biome (1.9.4)
[error] 116-117: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/features/projectsV2/ProjectsMap/microComponents/PlantLocations.tsx (2)
137-142
: Refactor the filtering logic for clarity.
These chained conditions can be extracted into a short helper function for better readability and maintainability.-const features = plantLocations.filter(d => - selectedIntervention === 'all' || - (selectedIntervention !== 'default' && d.type === selectedIntervention) || - (selectedIntervention === 'default' && - (d.type === 'multi-tree-registration' || d.type === 'single-tree-registration')) -).map((el) => { +const shouldInclude = (d: PlantLocation) => { + if (selectedIntervention === 'all') return true; + if (selectedIntervention === 'default') { + return d.type === 'multi-tree-registration' || d.type === 'single-tree-registration'; + } + return d.type === selectedIntervention; +}; +const features = plantLocations.filter(shouldInclude).map((el) => {
197-197
: Switch fallback color might need brand alignment.
If the satellite view color is hardcoded to#ffffff
, ensure this aligns with your brand guidelines. Otherwise, consider configuring a single color strategy.src/features/projectsV2/ProjectsMap/index.tsx (1)
179-181
: Keep naming straightforward.
mapContainerClass
merges base styles with the device-specific class. This is fine; just ensure the naming is intuitive for future contributors.src/features/projectsV2/ProjectsContext.tsx (1)
99-100
: Explicit types might be unnecessary.
As previously noted, TypeScript can infer the types from default values. Consider omitting them for brevity.src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss (4)
3-5
: Consider using more descriptive variable names.
Variables such as$layoutPaddingTop
and$layoutPaddingSide
are clear, but ensuring they reflect the intended usage (e.g.,$dropdownLayoutPaddingTop
) might aid future maintainers.
25-36
: Consider reusing classes for text styles.
.sitesLabel
and nestedspan
are well-structured, but watch for repeated patterns of color and font-size across the codebase to maintain consistency.
37-46
: Use variable for color.
Line 45 has a comment//to be replaced
. Consider referencing an SCSS variable from the theme to maintain consistency with the rest of your styling.
100-104
: Good approach to indicating selection state.
.selectedItem
clarifies the user’s active choice by increasing text weight. As noted, replace the hex color with a theme variable for consistency.src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss (1)
15-24
: Consider reusing existing .plantLocationInfoSection structure.
.otherInterventionInfoSection
essentially mirrors.plantLocationInfoSection
. Reusing a base class or applying a mixin could reduce CSS duplication.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
public/assets/images/icons/InterventionIcon.tsx
(1 hunks)src/features/common/types/plantLocation.d.ts
(2 hunks)src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/index.tsx
(3 hunks)src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss
(3 hunks)src/features/projectsV2/ProjectsContext.tsx
(5 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss
(1 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/MapControls.tsx
(4 hunks)src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss
(1 hunks)src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx
(4 hunks)src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss
(1 hunks)src/features/projectsV2/ProjectsMap/index.tsx
(4 hunks)src/features/projectsV2/ProjectsMap/microComponents/PlantLocations.tsx
(8 hunks)src/utils/constants/intervention.ts
(1 hunks)src/utils/mapsV2/zoomOut.tsx
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- public/assets/images/icons/InterventionIcon.tsx
🧰 Additional context used
🪛 GitHub Check: CodeFactor
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx
[notice] 9-9: src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx#L9
'type' is defined but never used. Allowed unused args must match /^_/u. (@typescript-eslint/no-unused-vars)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[warning] 87-87: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L87
Missing "key" prop for element in array (react/jsx-key)
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
[error] 63-73: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 52-53: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 69-75: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 116-117: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 87-87: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
🪛 GitHub Check: ESLint on Ubuntu
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[failure] 87-87:
Missing "key" prop for element in array
🪛 GitHub Actions: ESLint error report
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 87-87: Missing "key" prop for element in array (react/jsx-key)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (50)
src/features/projectsV2/ProjectsMap/ProjectsMap.module.scss (3)
14-14
: Ensure alignment is intentional.Switching to
justify-content: flex-end;
moves the items to the right. Verify that the right alignment aligns with the design specifications for desktop and mobile breakpoints.
16-16
: Responsive gap usage.Using
gap: 2vw;
is a great way to make spacing responsive. However, be mindful of extremely wide or narrow screens—vw
might lead to either too much or too little spacing in edge cases.
19-19
: Check container width constraints.Assigning
width: 85%
to a container withposition: absolute;
can be tricky. Confirm there are no unwanted overlaps or alignment issues on varied viewport sizes.src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx (1)
30-38
: Use a unique key and add accessibility attributes (duplicate of previous comment).Using the array index as a key can cause issues in dynamic lists and lead to suboptimal rendering behavior. Additionally, the list items do not provide accessibility hints for screen readers, such as
role="option"
and keyboard event handlers, to support accessibility.src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx (1)
69-70
: Avoid using array index as the key prop.
Usingkey={key}
can cause rendering issues when list items change order. Please switch to a more stable, unique identifier.src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx (1)
46-50
: Confirm the logic for disabling the dropdown menu.
Currently, the dropdown closes whendisableInterventionMenu === false
. If the intended behavior is to close it whendisableInterventionMenu === true
, consider updating the condition.useEffect(() => { - if(!disableInterventionMenu){ + if(disableInterventionMenu){ setIsMenuOpen(false) } }, [disableInterventionMenu])src/features/common/types/plantLocation.d.ts (1)
1-8
: Import and type usage look good.
The new propertytype: InterventionTypes
and its import appear consistent with the existing typings.src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/index.tsx (2)
80-84
: Ensure alignment between menu and intervention states.
Closing the dropdown whendisableInterventionMenu
is true is logical. Confirm that other features depending on menu availability also gracefully handle this condition.
90-93
: Verify if the menu toggle should always disable the intervention filter.
Currently, toggling the menu callsdisableInterventionFilter()
unconditionally. If the user intends to disable filtering only upon closing the menu, consider wrapping this logic with a condition.src/utils/constants/intervention.ts (6)
4-5
: Clarify identical color codes for SINGLE_TREE and MULTI_TREE
Both constants use the same hex color value (#007A49). Confirm whether this is intentional or if each intervention should have a distinct color to improve clarity and differentiation.
10-11
: Confirm usage of the term "regenerant"
It's unclear whether “regenerant” is domain-specific or a potential typo. If the term is correct, consider adding clarifying comments or references explaining its meaning to improve maintainability.
48-88
: Check for identical index values
All interventions here haveindex: 0
. If these indices are meant to be unique or arranged in a particular order, ensure that the values are properly maintained.
93-95
: Function behavior looks good
TheisNonPlantationType
helper accurately checks for non-plantation types.
98-100
: Usage of findMatchingIntervention
No concerns. This helper cleanly retrieves an intervention by value.
102-107
: Confirm multi-tree location guard
isPlantLocationMulti
is a logical type guard. Ensure all call sites handle the returned type correctly, especially when chaining with other location checks.src/features/projectsV2/ProjectsMap/MapControls.tsx (4)
64-66
: Inline or removeenableInterventionFilter
This function only callssetDisableInterventionMenu(true)
. In accordance with the previous suggestion (line 70 from older commits), consider removing it or inlining it directly to keep the code simpler and reduce indirection.- const enableInterventionFilter=()=>{ - setDisableInterventionMenu(true) - } + // Remove the function and call `setDisableInterventionMenu(true)` directly wherever needed
82-90
: Descriptive naming for props
InterventionDropdownProps
effectively conveys the needed props. Ensure naming consistency across similar objects (e.g.,siteDropdownProps
) and verify each property is used.
136-138
: Confirm layout spacing
When rendering bothProjectSiteDropdown
andInterventionDropDown
in mobile view, confirm that sufficient space is allocated to avoid unwanted overlapping.
150-153
: Desktop layout synergy
PlacingProjectSiteDropdown
andInterventionDropDown
side by side looks good. Validate hover or click behaviors are intuitive for desktop users.src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (1)
103-108
:⚠️ Potential issueDuplicate key "plantingDetails"
“plantingDetails” is used twice. Use distinct keys to avoid React warnings.<OtherInterventionInfoHeader - key="plantingDetails" + key="otherInterventionHeader" plantDate={plantLocationInfo?.interventionStartDate} type={plantLocationInfo?.type} />, checkForPublicData && <OtherInterventionMetaData - key="plantingDetails" + key="otherInterventionMetaData" ... />Likely invalid or redundant comment.
src/features/projectsV2/ProjectDetails/index.tsx (3)
26-27
: Good modularization
ImportingOtherInterventionInfo
andisNonPlantationType
from shared utilities centralizes intervention logic.
130-136
: Ensure clarity inshouldShowOtherIntervention
isNonPlantationType
is checked on bothhoveredPlantLocation
andselectedPlantLocation
, plus a!isMobile
check on only the latter. Confirm whether it’s deliberate that hovered non-plantation types appear on mobile but selected non-plantation types do not.
199-200
: Validate newOtherInterventionInfo
usage
The conditional rendering logic is straightforward. Confirm that the layout coexists cleanly withMultiPlantLocationInfo
andSinglePlantLocationInfo
components.src/features/projectsV2/ProjectsMap/microComponents/PlantLocations.tsx (6)
17-17
: Centralized color definition is good practice.
ImportingFillColor
from a constants file fosters maintainability and consistency.
27-27
: No immediate concerns with the new state usage.
TheselectedIntervention
addition aligns well with the filtering logic. Please ensure thorough testing wherever this state is accessed or modified.
151-151
: No issues with property assignment.
Including thetype
in GeoJSON properties is consistent for debugging or later usage.
170-170
: Centralized usage ofFillColor
is consistent.
Good job maintaining a single source of truth for color values.
179-179
: Uniform use ofFillColor
for circles.
This maintains consistency across different geometry types.
216-239
: Conditional rendering of sample markers looks correct.
The marker rendering logic appears coherent; ensure you have tests covering scenarios with and withoutsampleInterventions
.src/features/projectsV2/ProjectsMap/index.tsx (3)
27-28
: Useful additions for extended functionality.
ImportingOtherInterventionInfo
andPLANTATION_TYPES
is a clear step toward supporting multiple intervention types.
141-168
: Ensure user experience consistency on repeated clicks.
TheonClick
callback handles toggling plant locations. Consider verifying click behavior in edge cases (e.g., user double-clicks on multi-tree points repeatedly).
230-231
: Enhancement for secondary interventions.
Conditionally renderingOtherInterventionInfo
is a neat approach to handle non-plantation interventions.src/features/projectsV2/ProjectsContext.tsx (3)
61-64
: New fields in the interface appear consistent.
selectedIntervention
anddisableInterventionMenu
align with the broader interventions feature.
245-246
: Resetting intervention states on page change.
This effectively prevents carrying stale data from the project details to the project list. Provide test coverage for transitions.
Line range hint
451-475
: Well-organized context value.
The addition ofselectedIntervention
anddisableInterventionMenu
is structured properly in the context.src/features/projectsV2/ProjectsMap/ProjectSiteDropDown/SiteDropdown.module.scss (1)
145-145
: Consider the potential overlap.
Shiftingright
to40%
might cause layout overlap in certain screen widths. Verify positioning across device sizes.src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss (8)
1-2
: Import usage looks good.
Importing the theme at the top ensures consistent styling throughout.
21-24
: LGTM!
The layout for.siteIconAndTextContainer
is simple and straightforward.
47-55
: Handles icon sizing consistently.
The.menuArrow
class aligns icons consistently with the rest of the UI. This helps maintain uniform spacing across components.
56-77
: Beware of complex absolute positioning.
Positioning the dropdown absolutely can cause display issues in mobile or smaller layouts. Confirm this usage doesn’t clash with other components overlapping or going off-screen.
78-90
: Ensure consistent vertical spacing.
The.listItem
class sets gap and padding, which is good for readability. Just be sure that users don’t accidentally tap multiple items on mobile if the spacing is too tight.
91-99
: Conditional utility classes are a good pattern.
.hideDivider
and.showDivider
can be toggled dynamically, improving flexibility of the UI.
106-159
: Responsive tweaks appreciated.
The media query adjusts layout effectively for smaller screens. Monitor the real device testing to ensure the dropdown doesn’t overlap other critical UI elements.
6-20
: Ensure accessible contrast for background color.
The usage of$backgroundColor
in combination with text color should meet accessibility guidelines. Verify your color contrast ratio to ensure readability.✅ Verification successful
Color contrast appears to be sufficient with #333 text color
The dropdown uses #333 (dark gray) text color which typically provides excellent contrast against light backgrounds, meeting WCAG accessibility guidelines. The consistent use of this color combination across dropdown components suggests it's part of an accessible design system.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Use ast-grep or a color contrast checker to confirm background color contrast in .dropdownButton. # This script searches for the `.dropdownButton` definition and any usage of $backgroundColor. rg -A 5 $'\.dropdownButton'Length of output: 3869
Script:
#!/bin/bash # Search for backgroundColor variable definition and color-related variables rg -g '*.scss' -g '*.css' '\$backgroundColor' -A 2 rg -g '*.scss' -g '*.css' 'color:' -A 1 src/features/projectsV2/ProjectsMap/Length of output: 34868
src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss (6)
49-50
: Gap property is a welcome addition.
Increasing the gap for.plantingDetailsGroup
can improve readability.
53-56
: No concerns.
The.otherInterventionGroup
class is straightforward and uses a consistent font size.
58-62
: Good approach to highlight “Other Intervention” sections.
The background color and padding highlight these items well. Ensure they remain visually distinct for better user experience.
66-66
: Minor dimension update is consistent with the design standard.
Changing.plantingDetailsItem
from 162px to 160px should be verified across views to ensure it doesn’t break layout on smaller screens.
220-225
: Nice modular approach for metadata styling.
.interventionMetaItem
indicates a clear separation for each metadata entry. This can easily be reused for additional attributes in future expansions.
227-232
: Check label alignment.
If.plantMetaDataCardLabel
is intended to appear on top or inline with.interventionMetaItem
, verify the design requirement. Spacing might need adjusting for a consistent layout across different screen sizes.
const checkForPublicData = plantLocationInfo?.metadata.public.length !== 0 | ||
|
||
const content = [ | ||
<InterventionHeader plHid={plantLocationInfo?.hid} type={plantLocationInfo?.type} />, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Add unique keys to array elements
The review comment is correct. The InterventionHeader
component is rendered within an array and requires a key prop. Additionally, there's a duplicate key="plantingDetails" between OtherInterventionInfoHeader
and OtherInterventionMetaData
components that should be fixed.
- Add key="interventionHeader" to
InterventionHeader
- Change the key of
OtherInterventionMetaData
to key="interventionMetadata" to avoid duplicate keys
🔗 Analysis chain
Add a unique key property
When rendering an item within an array, React requires a unique key
.
- <InterventionHeader plHid={plantLocationInfo?.hid} type={plantLocationInfo?.type} />,
+ <InterventionHeader
+ key="interventionHeader"
+ plHid={plantLocationInfo?.hid}
+ type={plantLocationInfo?.type}
+ />,
🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts found
Script:
#!/bin/bash
# View the complete file content to understand the context
cat src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
Length of output: 4778
🧰 Tools
🪛 Biome (1.9.4)
[error] 87-87: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
🪛 GitHub Check: ESLint on Ubuntu
[failure] 87-87:
Missing "key" prop for element in array
🪛 GitHub Check: CodeFactor
[warning] 87-87: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L87
Missing "key" prop for element in array (react/jsx-key)
🪛 GitHub Actions: ESLint error report
[error] 87-87: Missing "key" prop for element in array (react/jsx-key)
.interventionMetaDataGroup { | ||
display: flex; | ||
flex-direction: column, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential syntax error.
In .interventionMetaDataGroup
, there's a comma instead of a semicolon on line 216. Sass might parse this incorrectly. Please confirm.
- flex-direction: column,
+ flex-direction: column;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
.interventionMetaDataGroup { | |
display: flex; | |
flex-direction: column, | |
.interventionMetaDataGroup { | |
display: flex; | |
flex-direction: column; | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx (1)
14-17
: Ensure an empty fallback is appropriateReturning an empty string might make debugging difficult if the intervention type is unexpected. Consider at least logging or handling an unknown type scenario for better maintainability.
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (2)
36-40
: Keep the interface separate if expansions are expectedThe
Props
interface is clearly defined. If more properties will be added in the future, consider placing it in a dedicated file for easier maintenance and reusability.
50-65
: Optional chaining recommendationThe static analysis hints suggest optional chaining, which can reduce repetitive checks. A minimal example within this block:
- (plantLocationInfo && - plantLocationInfo.plantedSpecies && - plantLocationInfo.plantedSpecies.length > 0) + (plantLocationInfo?.plantedSpecies?.length ?? 0) > 0🧰 Tools
🪛 Biome (1.9.4)
[error] 52-53: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 52-53: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 69-75: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 116-117: 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: Analyze (javascript)
🔇 Additional comments (6)
src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx (2)
5-8
: Good use of typed propsProviding explicit types for
plHid
andinterventionType
ensures clearer usage. Keep it up.
19-26
: Sensible layout with consistent namingUsing both a custom class (
plant-location-header-container
) and an SCSS module class helps maintain consistent styling throughout. The usage of descriptive class names liketree-count
andhid
is clear and aids readability.src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (4)
23-34
: Interface extension is well-structuredThe
OtherInterventions
interface extendsPlantLocationBase
and adds relevant fields for interventions. This approach cleanly organizes shared and specialized fields.
126-138
: Mobile and Desktop views are well-structuredYou’ve separated logic for mobile and desktop, improving clarity and user experience. Good approach.
67-78
:⚠️ Potential issuePrevent potential undefined array access
In line 68, you assume
plantLocationInfo.sampleInterventions.length > 0
. IfsampleInterventions
is undefined, this would throw an error. Safeguardino with optional chaining would improve stability:- if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { + if (plantLocationInfo?.sampleInterventions?.length > 0) {Likely invalid or redundant comment.
🧰 Tools
🪛 Biome (1.9.4)
[error] 69-75: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
86-124
:⚠️ Potential issueDuplicate key usage
At lines 99 and 104, the
key
isplantingDetails
for bothOtherInterventionInfoHeader
andOtherInterventionMetaData
. This causes a React warning for duplicate keys. Use distinct keys:+ <OtherInterventionInfoHeader + key="plantingDetailsHeader" ... />, - checkForPublicData && <OtherInterventionMetaData - key="plantingDetails" + checkForPublicData && <OtherInterventionMetaData + key="plantingDetailsMeta" ... />,Likely invalid or redundant comment.
🧰 Tools
🪛 Biome (1.9.4)
[error] 116-117: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
Outdated
Show resolved
Hide resolved
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shyambhongle Please go through my feedback.
Functionally, most things are fine, although I would combine some of the cards/sections together.
Please go through the code feedback, particular about cleaning up references to old code (e.g. sites) where they don't make sense any more, naming consistency, and the logic to keep only one dropdown open at a time.
In addition, I noticed that the code formatting differs, could you make sure the prettier rules aren't being overridden.
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
Show resolved
Hide resolved
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
Outdated
Show resolved
Hide resolved
src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss
Outdated
Show resolved
Hide resolved
@@ -92,6 +96,8 @@ export const ProjectsProvider: FC<ProjectsProviderProps> = ({ | |||
const [hoveredPlantLocation, setHoveredPlantLocation] = | |||
useState<PlantLocation | null>(null); | |||
const [selectedSite, setSelectedSite] = useState<number | null>(null); | |||
const [selectedIntervention, setSelectedIntervention] = useState('all'); | |||
const [disableInterventionMenu, setDisableInterventionMenu] = useState(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic to keep only one menu open is unclear, partly due to using terms like enable
and disable
instead of open
/close
/toggle
. The names disableInterventionMenu
, enableInterventionFilter
, disableInterventionFilter
need rethinking.
Please revisit this logic across the ProjectSiteDropdown
, InterventionDropdown
, ProjectsContext
and MapControls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a structure like this may be useful
const [activeDropdown, setActiveDropdown] = useState(null);
// In Site Dropdown
const toggleSiteMenu = () => {
setIsMenuOpen((prev) => !prev);
setActiveDropdown('site');
};
// In Intervention Dropdown
const toggleInterventionMenu = () => {
setIsMenuOpen((prev) => !prev);
setActiveDropdown('intervention');
};
There was a problem hiding this 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 (6)
src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx (1)
25-28
: Rename function to match its purpose.The function name
handleFilterSelection
should be renamed tohandleInterventionSelection
to better reflect its purpose.- const handleFilterSelection = (key: string) => { + const handleInterventionSelection = (key: string) => { setIsMenuOpen(false); setSelectedIntervention(key); };src/utils/constants/intervention.ts (1)
102-107
: Remove unused code.The
isPlantLocationMulti
function appears to be unused. Consider removing it if it's not needed.src/features/projectsV2/ProjectsMap/MapControls.tsx (2)
64-69
: Simplify state management.The
enableInterventionFilter
anddisableInterventionFilter
functions only set state. Consider callingsetDisableInterventionMenu
directly where needed.- const enableInterventionFilter=()=>{ - setDisableInterventionMenu(true) - } - const disableInterventionFilter=()=>{ - setDisableInterventionMenu(false) - }Update the usage:
- onClick={enableInterventionFilter} + onClick={() => setDisableInterventionMenu(true)}
82-91
: Use camelCase for variable names.Rename
InterventionDropdownProps
to follow JavaScript naming conventions.- const InterventionDropdownProps = { + const interventionDropdownProps = { selectedIntervention, setSelectedIntervention, allInterventions: AllInterventions, selectedPlantLocation, setSelectedPlantLocation, setSelectedSamplePlantLocation, enableInterventionFilter, disableInterventionMenu };src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (2)
34-45
: Consider making nullable fields optional in OtherInterventions interface.Fields that can be null should be marked as optional using the
?
operator for better type safety.export interface OtherInterventions extends PlantLocationBase { sampleTreeCount: number; sampleInterventions: SamplePlantLocation[]; plantedSpecies: PlantedSpecies[]; - nextMeasurementDate: null; - scientificName: string | null; - scientificSpecies: string | null; - tag: string | null; + nextMeasurementDate?: null; + scientificName?: string; + scientificSpecies?: string; + tag?: string; measurements: Measurements; originalGeometry: turf.Point; geometry: turf.Point; }
137-138
: Store and memoize metadata rendering result.The
renderMetaData()
result should be memoized to prevent unnecessary recalculations.-const checkForPublicData = renderMetaData() +const checkForPublicData = useMemo(() => renderMetaData(), [plantLocationInfo?.metadata]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
public/assets/images/icons/InterventionIcon.tsx
(1 hunks)src/features/common/types/plantLocation.d.ts
(2 hunks)src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss
(3 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/MapControls.tsx
(4 hunks)src/utils/constants/intervention.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- public/assets/images/icons/InterventionIcon.tsx
- src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
- src/features/common/types/plantLocation.d.ts
- src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 63-64: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 80-86: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 171-172: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
[error] 65-75: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx (1)
31-44
: Improve accessibility and list rendering.The list implementation needs improvements for accessibility and React best practices:
- Using index as key in map function is an anti-pattern
- Missing accessibility attributes for interactive elements
- Missing semantic HTML structure
- <ul className={styles.siteListOptions}> + <ul className={styles.interventionListOptions} role="listbox"> {interventionList.map((intervention) => { return ( <li - className={`${styles.listItem} ${intervention.value === selectedSiteData?.value ? styles.selectedItem : ''}`} - onClick={() => handleFilterSelection(intervention.value)} - key={index} + className={`${styles.listItem} ${intervention.value === selectedSiteData?.value ? styles.selectedItem : ''}`} + onClick={() => handleInterventionSelection(intervention.value)} + key={intervention.value} + role="option" + aria-selected={intervention.value === selectedSiteData?.value} + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleInterventionSelection(intervention.value); + } + }} > <p>{intervention.label}</p> </li> ); })} </ul>src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx (2)
48-52
: Fix the useEffect logic condition.The current logic seems reversed. The menu should close when
disableInterventionMenu
is true, not false.useEffect(() => { - if(!disableInterventionMenu){ + if(disableInterventionMenu){ setIsMenuOpen(false) } }, [disableInterventionMenu])
61-94
: Improve accessibility and remove unnecessary fragments.The dropdown button needs proper accessibility attributes and the code structure can be improved:
- Remove unnecessary fragment
- Add proper ARIA attributes for accessibility
- Move inline styles to CSS module
- <> - <div className={styles.dropdownButton} onClick={toggleMenu}> + <div + className={styles.dropdownButton} + onClick={toggleMenu} + role="button" + aria-haspopup="listbox" + aria-expanded={isMenuOpen} + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + toggleMenu(); + } + }} + > <div className={styles.siteIconAndTextContainer} > <InterventionIcon /> - <> {selectedSiteData && ( <div className={styles.labelTextContainer}> {isMobile ? <label className={styles.sitesLabel}> {truncateString(selectedSiteData?.label, 40)} </label> : - <p className={styles.siteName} style={{ marginTop: '5px' }}> + <p className={`${styles.siteName} ${styles.siteNameSpacing}`}> {truncateString(selectedSiteData?.label, 40)} </p>} </div> )} - </>Add to CSS module:
.siteNameSpacing { margin-top: 5px; }🧰 Tools
🪛 Biome (1.9.4)
[error] 65-75: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss (1)
214-216
:⚠️ Potential issueFix syntax error in CSS.
Replace the comma with a semicolon in the
.interventionMetaDataGroup
class..interventionMetaDataGroup { display: flex; - flex-direction: column, + flex-direction: column; }Likely invalid or redundant comment.
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (2)
78-89
: 🛠️ Refactor suggestionSimplify sampleInterventionSpeciesImages logic and add null checks.
The current implementation has redundant checks and potential null reference issues.
const sampleInterventionSpeciesImages = useMemo(() => { - if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { - const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { + if (plantLocationInfo?.sampleInterventions?.length > 0) { + return plantLocationInfo.sampleInterventions.map((item) => { return { id: item.coordinates[0].id, - image: item.coordinates[0].image ?? '', + image: item.coordinates[0]?.image ?? '', description: tProjectDetails('sampleTreeTag', { tag: item.tag }), }; }); - return result; } + return []; -}, [plantLocationInfo]); +}, [plantLocationInfo?.sampleInterventions, tProjectDetails]);Likely invalid or redundant comment.
🧰 Tools
🪛 Biome (1.9.4)
[error] 80-86: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
61-76
: Simplify totalTreesCount calculation using optional chaining.The current implementation has unnecessary complexity and can be simplified.
const { totalTreesCount } = useMemo(() => { const totalTreesCount = - plantLocationInfo && - plantLocationInfo.plantedSpecies && - plantLocationInfo.plantedSpecies.length > 0 + plantLocationInfo?.plantedSpecies?.length > 0 ? plantLocationInfo.plantedSpecies.reduce( (sum, species: { treeCount: number }) => sum + species.treeCount, 0 ) : 0; const area = plantLocationInfo?.geometry ? turf.area(plantLocationInfo?.geometry) : 0; const plantedLocationArea = area / 10000; return { totalTreesCount, plantedLocationArea }; -}, [plantLocationInfo?.geometry, plantLocationInfo?.type]); +}, [plantLocationInfo?.geometry, plantLocationInfo?.plantedSpecies]);The dependency array should include
plantLocationInfo.plantedSpecies
since it's used in the calculation.✅ Verification successful
Dependency array change is correct and necessary.
The suggested changes are valid because:
plantLocationInfo.plantedSpecies
is used in the calculation but missing from dependenciesplantLocationInfo.type
can be safely removed as it's not used within thisuseMemo
hook🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts found
Script:
#!/bin/bash # Get the complete file content to see all usages of plantLocationInfo.type cat src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx # Find imports of this component rg -l "OtherInterventionInfo" --type typescript --type tsx # Look for similar useMemo patterns with plantLocationInfo rg "plantLocationInfo\?.type" --type typescript --type tsx -A 2 -B 2Length of output: 6525
Script:
#!/bin/bash # Search for similar useMemo patterns with plantedSpecies rg "plantedSpecies" --type=ts --type=tsx -B 2 -A 2 # Look for other components that might be affected fd -e tsx -e ts | xargs grep -l "OtherInterventionInfo"Length of output: 468
🧰 Tools
🪛 Biome (1.9.4)
[error] 63-64: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
export const AllInterventions: Array<{ | ||
label: string | ||
value: INTERVENTION_TYPE | ||
index: number | ||
}> = [ | ||
{ | ||
label: 'All Intervention', | ||
value: 'all', | ||
index: 0, | ||
}, | ||
{ | ||
label: 'Single/Multi Tree Plantation', | ||
value: 'default', | ||
index: 1, | ||
}, | ||
{ | ||
label: 'Single Tree Plantation', | ||
value: 'single-tree-registration', | ||
index: 2, | ||
}, | ||
{ label: 'Multi Tree Plantation', value: 'multi-tree-registration', index: 3 }, | ||
{ label: 'Fire Patrol', value: 'fire-patrol', index: 4 }, | ||
{ label: 'Fire Suppression Team', value: 'fire-suppression', index: 5 }, | ||
{ label: 'Establish Fire Breaks', value: 'firebreaks', index: 6 }, | ||
{ label: 'Fencing', value: 'fencing', index: 7 }, | ||
{ | ||
label: 'Removal of Invasive Species', | ||
value: 'removal-invasive-species', | ||
index: 8, | ||
}, | ||
{ label: 'Direct Seeding', value: 'direct-seeding', index: 9 }, | ||
{ label: 'Grass Suppression', value: 'grass-suppression', index: 10 }, | ||
{ label: 'Marking Regenerant', value: 'marking-regenerant', index: 11 }, | ||
{ label: 'Enrichment Planting', value: 'enrichment-planting', index: 12 }, | ||
{ label: 'Liberating Regenerant', value: 'liberating-regenerant', index: 13 }, | ||
{ label: 'Soil Improvement', value: 'soil-improvement', index: 14 }, | ||
{ label: 'Assisting Seed Rain', value: 'assisting-seed-rain', index: 15 }, | ||
{ label: 'Stop Tree Harvesting', value: 'stop-tree-harvesting', index: 16 }, | ||
{ label: 'Maintenance', value: 'maintenance', index: 17 }, | ||
{ label: 'Other Intervention', value: 'other-intervention', index: 18 } | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve intervention configuration.
Several improvements needed:
- Labels should be translatable for internationalization
- The
index
property seems unnecessary as it's always sequential - Consider encapsulating color constants in an object for better maintainability
+import { useTranslation } from 'next-i18next';
+
+const interventionColors = {
+ SINGLE_TREE: '#007A49',
+ MULTI_TREE: '#007A49',
+ INVASIVE_SPECIES: '#EB5757',
+ // ... other colors
+};
+
export const AllInterventions: Array<{
label: string
value: INTERVENTION_TYPE
- index: number
}> = [
{
- label: 'All Intervention',
+ label: t('interventions.all'),
value: 'all',
- index: 0,
},
// ... other interventions
];
Committable suggestion skipped: line range outside the PR's diff.
const content = [ | ||
<InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" />, | ||
shouldDisplayImageCarousel && ( | ||
<ImageSlider | ||
key="imageSlider" | ||
images={sampleInterventionSpeciesImages} | ||
type="coordinate" | ||
isMobile={isMobile} | ||
imageSize="large" | ||
allowFullView={!isMobile} | ||
/> | ||
), | ||
<OtherInterventionInfoHeader | ||
key="plantingDetails" | ||
plantDate={plantLocationInfo?.interventionStartDate} | ||
type={plantLocationInfo?.type} | ||
/>, | ||
checkForPublicData.length > 0 && <OtherInterventionMetaData | ||
key="plantingDetails" | ||
metaData={checkForPublicData} | ||
plantDate={plantLocationInfo?.interventionStartDate} | ||
type={plantLocationInfo?.type} | ||
/>, | ||
plantLocationInfo?.plantedSpecies && plantLocationInfo.plantedSpecies.length > 0 && ( | ||
<SpeciesPlanted | ||
key="speciesPlanted" | ||
totalTreesCount={totalTreesCount} | ||
plantedSpecies={plantLocationInfo.plantedSpecies} | ||
/> | ||
), | ||
plantLocationInfo && | ||
plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.length > 0 && ( | ||
<SampleTrees | ||
key="sampleTrees" | ||
sampleInterventions={plantLocationInfo.sampleInterventions} | ||
setSelectedSamplePlantLocation={setSelectedSamplePlantLocation} | ||
/> | ||
), | ||
].filter(Boolean); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix duplicate keys and improve conditional rendering in content array.
There are several issues in the content array:
- Duplicate key "plantingDetails" between OtherInterventionInfoHeader and OtherInterventionMetaData
- Complex conditional rendering can be simplified
const content = [
<InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" />,
shouldDisplayImageCarousel && (
<ImageSlider
key="imageSlider"
images={sampleInterventionSpeciesImages}
type="coordinate"
isMobile={isMobile}
imageSize="large"
allowFullView={!isMobile}
/>
),
<OtherInterventionInfoHeader
key="plantingDetails"
plantDate={plantLocationInfo?.interventionStartDate}
type={plantLocationInfo?.type}
/>,
checkForPublicData.length > 0 && <OtherInterventionMetaData
- key="plantingDetails"
+ key="interventionMetaData"
metaData={checkForPublicData}
plantDate={plantLocationInfo?.interventionStartDate}
type={plantLocationInfo?.type}
/>,
plantLocationInfo?.plantedSpecies?.length > 0 && (
<SpeciesPlanted
key="speciesPlanted"
totalTreesCount={totalTreesCount}
plantedSpecies={plantLocationInfo.plantedSpecies}
/>
),
- plantLocationInfo &&
- plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.length > 0 && (
+ plantLocationInfo?.sampleInterventions?.length > 0 && (
<SampleTrees
key="sampleTrees"
sampleInterventions={plantLocationInfo.sampleInterventions}
setSelectedSamplePlantLocation={setSelectedSamplePlantLocation}
/>
),
].filter(Boolean);
Additionally, based on the past review comments, consider combining the image slider with the header component for better organization.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const content = [ | |
<InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" />, | |
shouldDisplayImageCarousel && ( | |
<ImageSlider | |
key="imageSlider" | |
images={sampleInterventionSpeciesImages} | |
type="coordinate" | |
isMobile={isMobile} | |
imageSize="large" | |
allowFullView={!isMobile} | |
/> | |
), | |
<OtherInterventionInfoHeader | |
key="plantingDetails" | |
plantDate={plantLocationInfo?.interventionStartDate} | |
type={plantLocationInfo?.type} | |
/>, | |
checkForPublicData.length > 0 && <OtherInterventionMetaData | |
key="plantingDetails" | |
metaData={checkForPublicData} | |
plantDate={plantLocationInfo?.interventionStartDate} | |
type={plantLocationInfo?.type} | |
/>, | |
plantLocationInfo?.plantedSpecies && plantLocationInfo.plantedSpecies.length > 0 && ( | |
<SpeciesPlanted | |
key="speciesPlanted" | |
totalTreesCount={totalTreesCount} | |
plantedSpecies={plantLocationInfo.plantedSpecies} | |
/> | |
), | |
plantLocationInfo && | |
plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.length > 0 && ( | |
<SampleTrees | |
key="sampleTrees" | |
sampleInterventions={plantLocationInfo.sampleInterventions} | |
setSelectedSamplePlantLocation={setSelectedSamplePlantLocation} | |
/> | |
), | |
].filter(Boolean); | |
const content = [ | |
<InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" />, | |
shouldDisplayImageCarousel && ( | |
<ImageSlider | |
key="imageSlider" | |
images={sampleInterventionSpeciesImages} | |
type="coordinate" | |
isMobile={isMobile} | |
imageSize="large" | |
allowFullView={!isMobile} | |
/> | |
), | |
<OtherInterventionInfoHeader | |
key="plantingDetails" | |
plantDate={plantLocationInfo?.interventionStartDate} | |
type={plantLocationInfo?.type} | |
/>, | |
checkForPublicData.length > 0 && <OtherInterventionMetaData | |
key="interventionMetaData" | |
metaData={checkForPublicData} | |
plantDate={plantLocationInfo?.interventionStartDate} | |
type={plantLocationInfo?.type} | |
/>, | |
plantLocationInfo?.plantedSpecies?.length > 0 && ( | |
<SpeciesPlanted | |
key="speciesPlanted" | |
totalTreesCount={totalTreesCount} | |
plantedSpecies={plantLocationInfo.plantedSpecies} | |
/> | |
), | |
plantLocationInfo?.sampleInterventions?.length > 0 && ( | |
<SampleTrees | |
key="sampleTrees" | |
sampleInterventions={plantLocationInfo.sampleInterventions} | |
setSelectedSamplePlantLocation={setSelectedSamplePlantLocation} | |
/> | |
), | |
].filter(Boolean); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 171-172: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (6)
src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx (1)
24-27
: Rename function for clarity.The function name
handleFilterSelection
should be renamed tohandleInterventionSelection
to better reflect its purpose.- const handleFilterSelection = (key: string) => { + const handleInterventionSelection = (key: string) => { setIsMenuOpen(false); setSelectedInterventionType(key); };src/utils/constants/intervention.ts (2)
1-2
: Remove unused import.The
PlantLocationMulti
type is imported but never used.import { DataDrivenPropertyValueSpecification } from "maplibre-gl"; -import { PlantLocation, PlantLocationMulti } from "../../features/common/types/plantLocation"; +import { PlantLocation } from "../../features/common/types/plantLocation";🧰 Tools
🪛 GitHub Check: CodeFactor
[notice] 2-2: src/utils/constants/intervention.ts#L2
'PlantLocationMulti' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
4-21
: Encapsulate color constants.For better maintainability, encapsulate the color constants in an object.
-const SINGLE_TREE = '#007A49'; -const MULTI_TREE = '#007A49'; -const INVASIVE_SPECIES = '#EB5757'; -// ... other color constants +const interventionColors = { + SINGLE_TREE: '#007A49', + MULTI_TREE: '#007A49', + INVASIVE_SPECIES: '#EB5757', + FIRE_SUPPRESSION: '#F2C94C', + FIRE_PATROL: '#F2994A', + FENCING: '#48AADD', + MARKING_REGENERANT: '#27AE60', + LIBERATING_REGENERANT: '#56CCF2', + GRASS_SUPPRESSION: '#219653', + FIREBREAKS: '#E86F56', + SEED_RAIN: '#2F80ED', + SOIL_IMPROVEMENT: '#6D4230', + STOP_HARVESTING: '#4F4F4F', + DIRECT_SEEDING: '#6FCF97', + ENRICHMENT_PLANTING: '#EB67CE', + MAINTENANCE: '#6C63FF', + OTHER_INTERVENTION: '#9B51E0' +} as const;src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (2)
61-76
: Simplify optional chaining and separate area calculation.The current implementation can be improved:
- Simplify the optional chaining operators
- Separate the area calculation for better memoization
const { totalTreesCount } = useMemo(() => { const totalTreesCount = - plantLocationInfo && - plantLocationInfo.plantedSpecies && - plantLocationInfo.plantedSpecies.length > 0 + plantLocationInfo?.plantedSpecies?.length > 0 ? plantLocationInfo.plantedSpecies.reduce( (sum, species: { treeCount: number }) => sum + species.treeCount, 0 ) : 0; + return { totalTreesCount }; +}, [plantLocationInfo?.plantedSpecies]); + +const plantedLocationArea = useMemo(() => { const area = plantLocationInfo?.geometry ? turf.area(plantLocationInfo?.geometry) : 0; - const plantedLocationArea = area / 10000; - return { totalTreesCount, plantedLocationArea }; -}, [plantLocationInfo?.geometry, plantLocationInfo?.type]); + return area / 10000; +}, [plantLocationInfo?.geometry]);🧰 Tools
🪛 Biome (1.9.4)
[error] 63-64: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
78-89
: Simplify sample interventions mapping and handle undefined case.The current implementation can be improved:
- Simplify the optional chaining
- Handle the undefined case explicitly
const sampleInterventionSpeciesImages = useMemo(() => { - if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { - const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { + if (plantLocationInfo?.sampleInterventions?.length > 0) { + return plantLocationInfo.sampleInterventions.map((item) => { return { id: item.coordinates[0].id, image: item.coordinates[0].image ?? '', description: tProjectDetails('sampleTreeTag', { tag: item.tag }), }; }); - return result; } + return []; }, [plantLocationInfo]);🧰 Tools
🪛 Biome (1.9.4)
[error] 80-86: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/features/projectsV2/ProjectsContext.tsx (1)
99-100
: Remove unnecessary type annotations.TypeScript can infer the types based on the initial values provided.
-const [selectedInterventionType, setSelectedInterventionType] = useState('all'); -const [disableInterventionMenu, setDisableInterventionMenu] = useState(false); +const [selectedInterventionType, setSelectedInterventionType] = useState('all'); +const [disableInterventionMenu, setDisableInterventionMenu] = useState(false);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/styles/PlantLocationInfo.module.scss
(4 hunks)src/features/projectsV2/ProjectsContext.tsx
(5 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss
(1 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/MapControls.tsx
(4 hunks)src/features/projectsV2/ProjectsMap/microComponents/PlantLocations.tsx
(8 hunks)src/utils/constants/intervention.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.module.scss
- src/features/projectsV2/ProjectDetails/components/microComponents/InterventionHeader.tsx
- src/features/projectsV2/ProjectsMap/microComponents/PlantLocations.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 63-64: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 80-86: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 172-173: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx
[error] 65-75: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
🪛 GitHub Check: CodeFactor
src/utils/constants/intervention.ts
[notice] 2-2: src/utils/constants/intervention.ts#L2
'PlantLocationMulti' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionHeader.tsx (1)
1-21
: LGTM!The component is well-structured with proper type definitions, conditional rendering, and CSS module usage.
src/features/projectsV2/ProjectsMap/InterventionDropDown/InterventionList.tsx (1)
30-43
: 🛠️ Refactor suggestionImprove accessibility and list rendering.
The list implementation needs improvements for accessibility and React best practices:
- Using index as key in map function is an anti-pattern
- Missing accessibility attributes
- Missing keyboard navigation support
- <ul className={styles.interventionListOptions}> + <ul className={styles.interventionListOptions} role="listbox"> {interventionList.map((intervention, index) => { return ( <li className={`${styles.listItem} ${intervention.value === selectedInterventionData?.value ? styles.selectedItem : ''}`} - onClick={() => handleFilterSelection(intervention.value)} - key={index} + onClick={() => handleInterventionSelection(intervention.value)} + key={intervention.value} + role="option" + aria-selected={intervention.value === selectedInterventionData?.value} + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleInterventionSelection(intervention.value); + } + }} > <p>{intervention.label}</p> </li> ); })} </ul>Likely invalid or redundant comment.
src/features/projectsV2/ProjectsMap/InterventionDropDown/index.tsx (1)
48-52
:⚠️ Potential issueFix the useEffect logic condition.
The current logic seems reversed. The menu should close when
disableInterventionMenu
is true, not false.useEffect(() => { - if(!disableInterventionMenu){ + if(disableInterventionMenu){ setIsMenuOpen(false) } }, [disableInterventionMenu])Likely invalid or redundant comment.
src/utils/constants/intervention.ts (1)
48-88
: 🛠️ Refactor suggestionImprove intervention configuration.
Several improvements needed:
- Labels should be translatable for internationalization
- The
index
property seems unnecessary as it's always sequential- Consider pluralizing variable names for clarity
+import { useTranslation } from 'next-i18next'; + -export const AllInterventions: Array<{ +export const AllInterventionTypes: Array<{ label: string value: INTERVENTION_TYPE - index: number }> = [ { - label: 'All Intervention', + label: t('interventions.all'), value: 'all', - index: 0, }, { - label: 'Single/Multi Tree Plantation', + label: t('interventions.default'), value: 'default', - index: 1, }, // ... other interventions with similar changes ];Likely invalid or redundant comment.
src/features/projectsV2/ProjectsMap/MapControls.tsx (1)
71-90
: 🛠️ Refactor suggestionUpdate props to match the suggested menu state management.
If you implement the suggested menu state management approach, update the props accordingly:
const siteDropdownProps = { selectedSite, setSelectedSite, projectSites: singleProject?.sites, selectedPlantLocation, setSelectedPlantLocation, setSelectedSamplePlantLocation, - disableInterventionFilter, - disableInterventionMenu + activeDropdown, + setActiveDropdown }; const interventionDropDownProps = { selectedInterventionType, setSelectedInterventionType, allInterventions: AllInterventions, selectedPlantLocation, setSelectedPlantLocation, setSelectedSamplePlantLocation, - enableInterventionFilter, - disableInterventionMenu + activeDropdown, + setActiveDropdown };Likely invalid or redundant comment.
src/features/projectsV2/ProjectsContext.tsx (1)
245-246
:⚠️ Potential issueAdd state setters to useEffect dependencies.
The effect resets intervention states but the corresponding state setters are missing from the dependency array.
}, [ page, + setSelectedInterventionType, + setDisableInterventionMenu, ]);Likely invalid or redundant comment.
<> | ||
<div className={styles.dropdownButton} onClick={toggleMenu}> | ||
<div className={styles.siteIconAndTextContainer} > | ||
<InterventionIcon /> | ||
<> | ||
{selectedSiteData && ( | ||
<div className={styles.labelTextContainer}> | ||
{isMobile ? <label className={styles.sitesLabel}>{truncateString(selectedSiteData?.label, 40)} | ||
</label> : | ||
<p className={styles.siteName} style={{ marginTop: '5px' }}> | ||
{truncateString(selectedSiteData?.label, 40)} | ||
</p>} | ||
</div> | ||
)} | ||
</> | ||
</div> | ||
<div className={styles.menuArrow}> | ||
{isMenuOpen ? ( | ||
<DropdownUpArrow width={10} /> | ||
) : ( | ||
<DropdownDownArrow width={10} /> | ||
)} | ||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve accessibility and remove unnecessary fragments.
The dropdown button needs proper accessibility attributes and the code structure can be improved:
- Remove unnecessary fragments
- Add proper ARIA attributes
- Move inline styles to CSS module
- <>
- <div className={styles.dropdownButton} onClick={toggleMenu}>
+ <div
+ className={styles.dropdownButton}
+ onClick={toggleMenu}
+ role="button"
+ aria-haspopup="listbox"
+ aria-expanded={isMenuOpen}
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ toggleMenu();
+ }
+ }}
+ >
<div className={styles.siteIconAndTextContainer} >
<InterventionIcon />
- <>
{selectedSiteData && (
<div className={styles.labelTextContainer}>
{isMobile ? <label className={styles.sitesLabel}>
{truncateString(selectedSiteData?.label, 40)}
</label> :
- <p className={styles.siteName} style={{ marginTop: '5px' }}>
+ <p className={`${styles.siteName} ${styles.siteNameSpacing}`}>
{truncateString(selectedSiteData?.label, 40)}
</p>}
</div>
)}
- </>
Add to CSS module:
.siteNameSpacing {
margin-top: 5px;
}
🧰 Tools
🪛 Biome (1.9.4)
[error] 65-75: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
.otherInterventionInfoSection { | ||
background: #fff; | ||
border-radius: 12px; | ||
margin-top: 23px; | ||
padding: 12px 12px 24px; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 15px; | ||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Address dropdown height and mobile view issues.
Per PR objectives, users reported that the intervention dropdown:
- Obscures the satellite switch feature
- Is taller than the site dropdown
- Overlaps with other dropdowns in mobile view
Add max-height and mobile-specific styles:
.otherInterventionInfoSection {
background: #fff;
border-radius: 12px;
margin-top: 23px;
padding: 12px 12px 24px;
display: flex;
flex-direction: column;
gap: 15px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);
max-height: 300px; // Add max-height
overflow-y: auto; // Enable scrolling
@media (max-width: 768px) {
max-height: 250px; // Smaller height for mobile
position: absolute;
z-index: 1; // Prevent overlap
}
}
const enableInterventionFilter=()=>{ | ||
setDisableInterventionMenu(true) | ||
} | ||
const disableInterventionFilter=()=>{ | ||
setDisableInterventionMenu(false) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve menu state management logic.
The current implementation has several issues:
- The naming is confusing as it uses "disable" and "enable" for what appears to be menu open/close operations.
- The functions only set state and could be simplified by directly calling
setDisableInterventionMenu
.
Consider this alternative approach for better clarity:
-const enableInterventionFilter=()=>{
- setDisableInterventionMenu(true)
-}
-const disableInterventionFilter=()=>{
- setDisableInterventionMenu(false)
-}
+const [activeDropdown, setActiveDropdown] = useState<'site' | 'intervention' | null>(null);
+
+const toggleInterventionMenu = () => {
+ setActiveDropdown((prev) => prev === 'intervention' ? null : 'intervention');
+};
This approach:
- Uses clear naming that reflects the actual operation
- Manages which dropdown is currently active
- Allows only one dropdown to be open at a time
Committable suggestion skipped: line range outside the PR's diff.
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
src/utils/constants/intervention.ts (2)
4-20
: Encapsulate color constants in an object for better maintainability.Consider grouping the color constants in an object to improve code organization and make it easier to maintain color themes.
-const SINGLE_TREE = '#007A49'; -const MULTI_TREE = '#007A49'; -const INVASIVE_SPECIES = '#EB5757'; -// ... other color constants +const interventionColors = { + SINGLE_TREE: '#007A49', + MULTI_TREE: '#007A49', + INVASIVE_SPECIES: '#EB5757', + // ... other colors +} as const;
22-44
: Consider using a distinctive default color.The current implementation uses
SINGLE_TREE
color as the default case. Consider using a more distinctive color for unmatched types to make them easily identifiable on the map.export const FillColor: DataDrivenPropertyValueSpecification<string> = [ 'match', ['get', 'type'], // ... existing matches - SINGLE_TREE + '#CCCCCC' // neutral gray for unmatched types ]src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (3)
1-22
: Remove unused imports.The following imports are not used in the code:
Measurements
PlantLocationMulti
turf
import type { - Measurements, PlantedSpecies, PlantLocationBase, - PlantLocationMulti, SamplePlantLocation, } from '../../../common/types/plantLocation'; import type { SetState } from '../../../common/types/common'; import { useMemo } from 'react'; import { useTranslations } from 'next-intl'; -import * as turf from '@turf/turf'; import styles from '../styles/PlantLocationInfo.module.scss';🧰 Tools
🪛 GitHub Check: CodeFactor
[notice] 2-2: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L2
'Measurements' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
[notice] 12-12: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L12
'turf' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
[notice] 5-5: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L5
'PlantLocationMulti' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
55-66
: Simplify totalTreesCount calculation using optional chaining.The current implementation has unnecessary complexity in the null checks.
const { totalTreesCount } = useMemo(() => { const totalTreesCount = - plantLocationInfo && - plantLocationInfo.plantedSpecies && - plantLocationInfo.plantedSpecies.length > 0 + plantLocationInfo?.plantedSpecies?.length > 0 ? plantLocationInfo.plantedSpecies.reduce( (sum, species: { treeCount: number }) => sum + species.treeCount, 0 ) : 0; return { totalTreesCount }; }, [plantLocationInfo, plantLocationInfo?.type]);🧰 Tools
🪛 Biome (1.9.4)
[error] 57-58: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
68-79
: Simplify sampleInterventionSpeciesImages logic.The current implementation has unnecessary complexity and potential undefined access.
const sampleInterventionSpeciesImages = useMemo(() => { - if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { - const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { + if (plantLocationInfo?.sampleInterventions?.length > 0) { + return plantLocationInfo.sampleInterventions.map((item) => { return { id: item.coordinates[0].id, - image: item.coordinates[0].image ?? '', + image: item.coordinates[0]?.image ?? '', description: tProjectDetails('sampleTreeTag', { tag: item.tag }), }; }); - return result; } + return []; }, [plantLocationInfo]);🧰 Tools
🪛 Biome (1.9.4)
[error] 70-76: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/features/common/types/plantLocation.d.ts
(2 hunks)src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectsMap/index.tsx
(4 hunks)src/utils/constants/intervention.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/features/common/types/plantLocation.d.ts
- src/features/projectsV2/ProjectsMap/index.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 57-58: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 70-76: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 162-163: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 GitHub Check: CodeFactor
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[notice] 2-2: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L2
'Measurements' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
[notice] 12-12: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L12
'turf' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
[notice] 5-5: src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx#L5
'PlantLocationMulti' is defined but never used. Allowed unused vars must match /^_/u. (@typescript-eslint/no-unused-vars)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
src/utils/constants/intervention.ts (4)
45-45
: LGTM! Comprehensive type definition.The
INTERVENTION_TYPE
union type is well-defined and includes all necessary intervention types along with special values.
90-90
: LGTM! Well-defined plantation types.The
PLANTATION_TYPES
constant correctly identifies the plantation-specific intervention types.
93-95
: LGTM! Robust type checking.The helper function correctly handles null cases and uses proper type checking.
48-88
: 🛠️ Refactor suggestionImprove intervention configuration.
Several improvements needed:
- The
index
property seems unnecessary as it's always sequential- Labels should be translatable for internationalization
+import { useTranslations } from 'next-i18next'; + export const AllInterventions: Array<{ label: string value: INTERVENTION_TYPE - index: number }> = [ { - label: 'All Intervention', + label: t('interventions.all'), value: 'all', - index: 0, }, // ... other interventions ];Likely invalid or redundant comment.
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (1)
131-170
:⚠️ Potential issueFix duplicate keys and simplify conditional rendering.
Several issues need to be addressed:
- Duplicate key "interventionHeader" between components
- Complex conditional rendering that can be simplified using optional chaining
const content = [ <> <InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" /> {shouldDisplayImageCarousel && ( <ImageSlider key="imageSlider" images={sampleInterventionSpeciesImages} type="coordinate" isMobile={isMobile} imageSize="large" allowFullView={!isMobile} /> )} </>, <OtherInterventionInfoHeader - key="interventionHeader" + key="otherInterventionHeader" plantDate={plantLocationInfo?.interventionStartDate} />, checkForPublicData.length > 0 && <OtherInterventionMetaData key="plantingDetails" metaData={checkForPublicData} plantDate={plantLocationInfo?.interventionStartDate} type={plantLocationInfo?.type} />, plantLocationInfo?.plantedSpecies?.length > 0 && ( <SpeciesPlanted key="speciesPlanted" totalTreesCount={totalTreesCount} plantedSpecies={plantLocationInfo.plantedSpecies} /> ), - plantLocationInfo && - plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.length > 0 && ( + plantLocationInfo?.sampleInterventions?.length > 0 && ( <SampleTrees key="sampleTrees" sampleInterventions={plantLocationInfo.sampleInterventions} setSelectedSamplePlantLocation={setSelectedSamplePlantLocation} /> ), ].filter(Boolean);Likely invalid or redundant comment.
🧰 Tools
🪛 Biome (1.9.4)
[error] 162-163: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
There was a problem hiding this 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 (1)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (1)
128-167
:⚠️ Potential issueFix duplicate keys and improve content organization.
There are several issues in the content array that need to be addressed:
- Duplicate key "interventionHeader" between components
- Complex conditional rendering that can be simplified
- Consider combining the header with image slider as suggested in past reviews
const content = [ - <> + <div key="headerSection"> <InterventionHeader plHid={plantLocationInfo?.hid} interventionType={plantLocationInfo?.type} key="interventionHeader" /> {shouldDisplayImageCarousel && ( <ImageSlider key="imageSlider" images={sampleInterventionSpeciesImages} type="coordinate" isMobile={isMobile} imageSize="large" allowFullView={!isMobile} /> )} - </>, + </div>, <OtherInterventionInfoHeader - key="interventionHeader" + key="otherInterventionHeader" plantDate={plantLocationInfo?.interventionStartDate} />, cleanedPublicMetadata.length > 0 && <OtherInterventionMetaData key="plantingDetails" metaData={cleanedPublicMetadata} plantDate={plantLocationInfo?.interventionStartDate} type={plantLocationInfo?.type} />, - plantLocationInfo?.plantedSpecies && plantLocationInfo.plantedSpecies.length > 0 && ( + plantLocationInfo?.plantedSpecies?.length > 0 && ( <SpeciesPlanted key="speciesPlanted" totalTreesCount={totalTreesCount} plantedSpecies={plantLocationInfo.plantedSpecies} /> ), - plantLocationInfo && - plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.length > 0 && ( + plantLocationInfo?.sampleInterventions?.length > 0 && ( <SampleTrees key="sampleTrees" sampleInterventions={plantLocationInfo.sampleInterventions} setSelectedSamplePlantLocation={setSelectedSamplePlantLocation} /> ), ].filter(Boolean);🧰 Tools
🪛 Biome (1.9.4)
[error] 159-160: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🧹 Nitpick comments (3)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx (3)
24-30
: Remove extra blank lines between interface definitions.Maintain consistent spacing with a single blank line between interfaces for better code organization.
} - - interface PublicMetaData { [key: string]: string | MetaDataValue; } -
94-122
: Refactor createCardData for better maintainability.The function has complex nested logic that could be simplified by extracting the value processing logic into a separate function.
+ const processMetadataValue = (value: string | MetaDataValue, key: string) => { + if (typeof value === 'string') { + return { value, key }; + } + + if (typeof value === 'object' && value !== null && 'value' in value && 'label' in value) { + if (isJsonString(value.value)) { + try { + const parsedValue = JSON.parse(value.value); + if (parsedValue && typeof parsedValue === 'object' && 'value' in parsedValue) { + return { value: parsedValue.value, key: value.label }; + } + } catch (error) { + console.error('Error parsing JSON:', error); + } + } + return { value: value.value, key: value.label }; + } + return null; + }; + const createCardData = () => { const checkForPublic: { key: string; value: string }[] = []; const parsedData = plantLocationInfo?.metadata; if (parsedData?.public && typeof parsedData.public === 'object' && !Array.isArray(parsedData.public)) { Object.entries(parsedData.public as PublicMetaData).forEach(([key, value]) => { - if (key !== 'isEntireSite') { - if (typeof value === 'string') { - checkForPublic.push({ value, key }); - } else if (typeof value === 'object' && value !== null && 'value' in value && 'label' in value) { - if (isJsonString(value.value)) { - try { - const parsedValue = JSON.parse(value.value); - if (parsedValue && typeof parsedValue === 'object' && 'value' in parsedValue) { - checkForPublic.push({ value: parsedValue.value, key: value.label }); - } - } catch (error) { - console.error('Error parsing JSON:', error); - } - } else { - checkForPublic.push({ value: value.value, key: value.label }); - } - } + if (key !== 'isEntireSite') { + const processed = processMetadataValue(value, key); + if (processed) { + checkForPublic.push(processed); + } } }); }
168-175
: Remove unnecessary fragment wrapper.The fragment wrapper around MobileInfoSwiper is not needed as there's only one child element.
return isMobile ? ( - <> <MobileInfoSwiper slides={content} uniqueKey={plantLocationInfo?.hid || ''} /> - </> ) : (
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
(1 hunks)src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/projectsV2/ProjectDetails/components/microComponents/OtherInterventionMetaData.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/projectsV2/ProjectDetails/components/OtherInterventionInfo.tsx
[error] 54-55: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 67-73: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 159-160: 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: Analyze (javascript)
const { totalTreesCount } = useMemo(() => { | ||
const totalTreesCount = | ||
plantLocationInfo && | ||
plantLocationInfo.plantedSpecies && | ||
plantLocationInfo.plantedSpecies.length > 0 | ||
? plantLocationInfo.plantedSpecies.reduce( | ||
(sum, species: { treeCount: number }) => sum + species.treeCount, | ||
0 | ||
) | ||
: 0; | ||
return { totalTreesCount }; | ||
}, [plantLocationInfo, plantLocationInfo?.type]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simplify totalTreesCount calculation using optional chaining.
The current implementation has unnecessary complexity and can be simplified.
const { totalTreesCount } = useMemo(() => {
const totalTreesCount =
- plantLocationInfo &&
- plantLocationInfo.plantedSpecies &&
- plantLocationInfo.plantedSpecies.length > 0
+ plantLocationInfo?.plantedSpecies?.length > 0
? plantLocationInfo.plantedSpecies.reduce(
(sum, species: { treeCount: number }) => sum + species.treeCount,
0
)
: 0;
return { totalTreesCount };
- }, [plantLocationInfo, plantLocationInfo?.type]);
+ }, [plantLocationInfo?.plantedSpecies]);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const { totalTreesCount } = useMemo(() => { | |
const totalTreesCount = | |
plantLocationInfo && | |
plantLocationInfo.plantedSpecies && | |
plantLocationInfo.plantedSpecies.length > 0 | |
? plantLocationInfo.plantedSpecies.reduce( | |
(sum, species: { treeCount: number }) => sum + species.treeCount, | |
0 | |
) | |
: 0; | |
return { totalTreesCount }; | |
}, [plantLocationInfo, plantLocationInfo?.type]); | |
const { totalTreesCount } = useMemo(() => { | |
const totalTreesCount = | |
plantLocationInfo?.plantedSpecies?.length > 0 | |
? plantLocationInfo.plantedSpecies.reduce( | |
(sum, species: { treeCount: number }) => sum + species.treeCount, | |
0 | |
) | |
: 0; | |
return { totalTreesCount }; | |
}, [plantLocationInfo?.plantedSpecies]); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 54-55: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
const sampleInterventionSpeciesImages = useMemo(() => { | ||
if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { | ||
const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { | ||
return { | ||
id: item.coordinates[0].id, | ||
image: item.coordinates[0].image ?? '', | ||
description: tProjectDetails('sampleTreeTag', { tag: item.tag }), | ||
}; | ||
}); | ||
return result; | ||
} | ||
}, [plantLocationInfo]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simplify sampleInterventionSpeciesImages logic and add return type.
The current implementation has unnecessary complexity and lacks a return type annotation.
- const sampleInterventionSpeciesImages = useMemo(() => {
+ const sampleInterventionSpeciesImages = useMemo((): Array<{
+ id: string;
+ image: string;
+ description: string;
+ }> => {
- if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) {
- const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => {
+ if (plantLocationInfo?.sampleInterventions?.length > 0) {
+ return plantLocationInfo.sampleInterventions.map((item) => {
return {
id: item.coordinates[0].id,
- image: item.coordinates[0].image ?? '',
+ image: item.coordinates[0]?.image ?? '',
description: tProjectDetails('sampleTreeTag', { tag: item.tag }),
};
});
- return result;
}
+ return [];
}, [plantLocationInfo]);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const sampleInterventionSpeciesImages = useMemo(() => { | |
if (plantLocationInfo && plantLocationInfo.sampleInterventions.length > 0) { | |
const result = plantLocationInfo.sampleInterventions && plantLocationInfo.sampleInterventions.map((item) => { | |
return { | |
id: item.coordinates[0].id, | |
image: item.coordinates[0].image ?? '', | |
description: tProjectDetails('sampleTreeTag', { tag: item.tag }), | |
}; | |
}); | |
return result; | |
} | |
}, [plantLocationInfo]); | |
const sampleInterventionSpeciesImages = useMemo((): Array<{ | |
id: string; | |
image: string; | |
description: string; | |
}> => { | |
if (plantLocationInfo?.sampleInterventions?.length > 0) { | |
return plantLocationInfo.sampleInterventions.map((item) => { | |
return { | |
id: item.coordinates[0].id, | |
image: item.coordinates[0]?.image ?? '', | |
description: tProjectDetails('sampleTreeTag', { tag: item.tag }), | |
}; | |
}); | |
} | |
return []; | |
}, [plantLocationInfo]); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 67-73: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
Fixes #
Changes in this pull request:
Displaying other interventions in the web app.