-
Notifications
You must be signed in to change notification settings - Fork 649
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
Fix: Facility Organization Dropdown #10104
Conversation
Caution Review failedThe pull request is closed. WalkthroughThis pull request modifies the Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
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 (
|
❌ Deploy Preview for care-ohc failed.
|
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 (1)
src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx (1)
115-126
: Consider adding ARIA attributes for better accessibility.The new organization display looks great with the Building icon and clear visual hierarchy. Consider these accessibility improvements:
- <div className="flex items-center gap-3 rounded-md border border-sky-100 bg-sky-50/50 p-2.5"> + <div + className="flex items-center gap-3 rounded-md border border-sky-100 bg-sky-50/50 p-2.5" + role="status" + aria-label={`Selected organization: ${selectedOrganization.name}`} + > <Building className="h-4 w-4 text-sky-600 flex-shrink-0" aria-hidden="true" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx
(2 hunks)
🔇 Additional comments (2)
src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx (2)
2-2
: LGTM! Good choice of icon library.The addition of the Building icon from lucide-react aligns with the PR objectives and follows good practices.
172-176
: LGTM! Well-implemented dynamic placeholder with i18n support.The placeholder text implementation provides clear context and properly supports internationalization.
<div key={org.id} className="flex items-center gap-1.5"> | ||
<div className="flex items-center gap-1.5 flex-1"> | ||
{index > 0 && ( | ||
<CareIcon | ||
icon="l-arrow-right" | ||
className="h-3.5 w-3.5 text-gray-400 flex-shrink-0" | ||
/> | ||
)} | ||
<div | ||
className="flex items-center justify-between flex-1 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-sm shadow-sm cursor-pointer hover:bg-gray-50" | ||
onClick={() => handleEdit(index)} | ||
> | ||
<span className="truncate">{org.name}</span> | ||
<CareIcon | ||
icon="l-angle-down" | ||
className="h-3.5 w-3.5 ml-2 flex-shrink-0 text-gray-400" | ||
/> | ||
</div> | ||
</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
Enhance keyboard accessibility for interactive elements.
The hierarchical display looks clean, but needs accessibility improvements for keyboard users:
<div
- className="flex items-center justify-between flex-1 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-sm shadow-sm cursor-pointer hover:bg-gray-50"
+ className="flex items-center justify-between flex-1 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-sm shadow-sm cursor-pointer hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
+ role="button"
+ tabIndex={0}
onClick={() => handleEdit(index)}
+ onKeyDown={(e) => e.key === 'Enter' && handleEdit(index)}
+ aria-label={`Edit ${org.name} level`}
📝 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.
<div key={org.id} className="flex items-center gap-1.5"> | |
<div className="flex items-center gap-1.5 flex-1"> | |
{index > 0 && ( | |
<CareIcon | |
icon="l-arrow-right" | |
className="h-3.5 w-3.5 text-gray-400 flex-shrink-0" | |
/> | |
)} | |
<div | |
className="flex items-center justify-between flex-1 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-sm shadow-sm cursor-pointer hover:bg-gray-50" | |
onClick={() => handleEdit(index)} | |
> | |
<span className="truncate">{org.name}</span> | |
<CareIcon | |
icon="l-angle-down" | |
className="h-3.5 w-3.5 ml-2 flex-shrink-0 text-gray-400" | |
/> | |
</div> | |
</div> | |
</div> | |
<div key={org.id} className="flex items-center gap-1.5"> | |
<div className="flex items-center gap-1.5 flex-1"> | |
{index > 0 && ( | |
<CareIcon | |
icon="l-arrow-right" | |
className="h-3.5 w-3.5 text-gray-400 flex-shrink-0" | |
/> | |
)} | |
<div | |
className="flex items-center justify-between flex-1 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-sm shadow-sm cursor-pointer hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2" | |
role="button" | |
tabIndex={0} | |
onClick={() => handleEdit(index)} | |
onKeyDown={(e) => e.key === 'Enter' && handleEdit(index)} | |
aria-label={`Edit ${org.name} level`} | |
> | |
<span className="truncate">{org.name}</span> | |
<CareIcon | |
icon="l-angle-down" | |
className="h-3.5 w-3.5 ml-2 flex-shrink-0 text-gray-400" | |
/> | |
</div> | |
</div> | |
</div> |
When you click on the dropdown that already has a value selected, the expected behavior is for the dropdown options to be displayed. Instead, the current behavior is that it closes the entire dropdown and reset it to its initial state, as if no value was previously selected. @Jeffrin2005 https://www.loom.com/share/8cb97e50e22a45f98702f155c1ae9685?sid=6d2cc770-b044-409c-9801-2e665845b678 |
v23.mp4Any Changes required ? |
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 (1)
src/components/ui/autocomplete.tsx (1)
Line range hint
33-47
: Consider adding controlled open state prop.To provide more flexibility and better control over the dropdown's behavior, consider making the open state controllable from the parent component.
Add an optional prop for controlled open state:
interface AutocompleteProps { options: AutoCompleteOption[]; value: string; onChange: (value: string) => void; onSearch?: (value: string) => void; placeholder?: string; noOptionsMessage?: string; disabled?: boolean; align?: "start" | "center" | "end"; popoverClassName?: string; "data-cy"?: string; + open?: boolean; + onOpenChange?: (open: boolean) => void; }This would allow parent components to have full control over the dropdown's open state when needed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/ui/autocomplete.tsx
(2 hunks)src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx
🔇 Additional comments (2)
src/components/ui/autocomplete.tsx (2)
52-52
: LGTM! Good optimization.The introduction of
selectedOption
improves code readability and reduces repeated lookups.
67-73
: LGTM! Clean implementation.The label display logic is well-structured with good separation of styling and content.
src/components/ui/autocomplete.tsx
Outdated
onChange(currentValue); | ||
setOpen(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.
Optimize onSelect handler to prevent unnecessary updates.
The current implementation doesn't check if the selected value is different from the current value, which could lead to unnecessary re-renders and might contribute to the reported dropdown behavior issues.
Apply this optimization:
- onChange(currentValue);
- setOpen(false);
+ if (currentValue !== value) {
+ onChange(currentValue);
+ setOpen(false);
+ }
📝 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.
onChange(currentValue); | |
setOpen(false); | |
}} | |
if (currentValue !== value) { | |
onChange(currentValue); | |
setOpen(false); | |
} |
src/components/ui/autocomplete.tsx
Outdated
<span | ||
className={cn( | ||
"truncate", | ||
!selectedOption && "text-muted-foreground", |
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.
are you sure this is a valid tailwind class?
{selectedOrganization.has_children && ( | ||
<Badge variant="outline">Has Sub-departments</Badge> | ||
<p className="text-xs text-sky-600"> | ||
{t("Has Sub Departments")} |
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.
refer translations guidelines in README. this is not how i18n should be done.
if (level < selectedLevels.length) { | ||
return selectedLevels[level].name; | ||
} | ||
return level === 0 ? t("select_department") : t("select sub department"); |
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.
please check all translations
@rithviknishad Updated all transitions. |
src/pages/FacilityOrganization/components/FacilityOrganizationSelector.tsx
Outdated
Show resolved
Hide resolved
<div | ||
className="cursor-pointer p-1 hover:bg-gray-100 rounded-sm opacity-0 group-hover:opacity-100 transition-opacity" | ||
onClick={() => { | ||
const newLevels = selectedLevels.slice(0, level); |
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.
This logic is what should be in a function called handleEdit 👍
Separate out the concerns, code readability is important (check GovtOrganizationSelector for example for similar logic).
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 (2)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (1)
64-68
: Reduce code duplication when retrievingorgList
.The logic to retrieve
orgList
from eitherrootOrganizations
ororganizationQueries
appears in bothhandleLevelChange
andrenderOrganizationLevel
. Extract this repeated pattern into a shared helper function to conform to DRY principles and improve maintainability.Also applies to: 107-111
src/components/ui/autocomplete.tsx (1)
125-125
: Fix indentation for compliance with lint rules.Prettier highlights a missing indentation at line 125. Applying the following diff should resolve the linter error:
-const selectedOption = options.find((option) => option.value === value); + const selectedOption = options.find((option) => option.value === value);🧰 Tools
🪛 ESLint
[error] 125-125: Insert
··
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
[failure] 125-125:
Insert··
🪛 GitHub Check: lint
[failure] 125-125:
Insert··
🪛 GitHub Actions: Lint Code Base
[error] 125-125: Insert
··
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
public/locale/en.json
(2 hunks)src/components/ui/autocomplete.tsx
(3 hunks)src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- public/locale/en.json
🧰 Additional context used
🪛 ESLint
src/components/ui/autocomplete.tsx
[error] 125-125: Insert ··
(prettier/prettier)
[error] 149-152: Replace ⏎⏎········<Command>{commandContent}</Command>⏎
with ········<Command>{commandContent}</Command>
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
src/components/ui/autocomplete.tsx
[failure] 125-125:
Insert ··
[failure] 149-149:
Replace ⏎⏎········<Command>{commandContent}</Command>⏎
with ········<Command>{commandContent}</Command>
🪛 GitHub Check: lint
src/components/ui/autocomplete.tsx
[failure] 125-125:
Insert ··
[failure] 149-149:
Replace ⏎⏎········<Command>{commandContent}</Command>⏎
with ········<Command>{commandContent}</Command>
🪛 GitHub Actions: Lint Code Base
src/components/ui/autocomplete.tsx
[error] 125-125: Insert ··
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: OSSAR-Scan
🔇 Additional comments (3)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (1)
157-166
: UI enhancement with building icon.Showing the building icon in a distinct color thoroughly clarifies the currently selected organization. Great job on the user experience design!
src/components/ui/autocomplete.tsx (2)
137-137
: Restore dropdown toggle on repeated clicks.Past feedback highlighted that forcing
setOpen(true)
prevents toggling the dropdown closed. Switching tosetOpen(!open)
preserves the ability for users to click the button again to close the menu.
63-63
: Reintroduce focus outlines for accessibility.Previously noted: removing all outlines (via
"outline-none border-none ring-0 shadow-none"
) can hinder keyboard navigation. Preserving or customizing focus indicators helps users relying on tab navigation, for example:- className="outline-none border-none ring-0 shadow-none" + className="focus:ring-2 focus:ring-offset-2 focus:ring-primary"
const organizationQueries = useQueries({ | ||
queries: selectedLevels.map((level, _index) => ({ | ||
queryKey: ["organizations", level.id], | ||
queryFn: query(routes.facilityOrganization.list, { | ||
pathParams: { facilityId }, | ||
queryParams: { parent: level.id }, | ||
}), | ||
enabled: !!level.id, | ||
})), |
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
Add error or loading states for sub-organization queries.
If a sub-organization query fails or is still loading, the user has no feedback. Consider displaying a loading indicator or error message for each query, ensuring a smoother user experience when fetching data asynchronously.
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: 0
🔭 Outside diff range comments (2)
src/components/ui/autocomplete.tsx (2)
67-74
: Fix dropdown selection behavior.The current implementation has two issues:
- It doesn't properly handle the toggle case, causing the reported issue where "dropdown closes when clicked with a value selected"
- It doesn't optimize for unnecessary updates
Apply these fixes:
- onSelect={(v) => { - const currentValue = - options.find( - (option) => option.label.toLowerCase() === v.toLowerCase(), - )?.value || ""; - onChange(currentValue === value ? "" : currentValue); - setOpen(false); - }} + onSelect={(v) => { + const currentValue = + options.find( + (option) => option.label.toLowerCase() === v.toLowerCase(), + )?.value || ""; + if (currentValue !== value) { + onChange(currentValue); + } + setOpen(!open); + }}
105-105
: Fix mobile dropdown toggle behavior.The mobile implementation has the same toggle issue where clicking doesn't properly toggle the dropdown state.
- onClick={() => setOpen(true)} + onClick={() => setOpen(!open)}
🧹 Nitpick comments (3)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (3)
99-142
: Consider memoizing the renderOrganizationLevel function.The function creates new components on each render. Consider using
useCallback
to memoize the function anduseMemo
for the dropdown label to optimize performance.- const renderOrganizationLevel = (level: number) => { + const renderOrganizationLevel = useCallback((level: number) => { let orgList: FacilityOrganization[] | undefined; if (level === 0) { orgList = rootOrganizations?.results; } else if (level - 1 < organizationQueries.length) { orgList = organizationQueries[level - 1].data?.results; } - const getDropdownLabel = () => { + const dropdownLabel = useMemo(() => { if (level < selectedLevels.length) { return selectedLevels[level].name; } return level === 0 ? t("select_department") : t("select_sub_department"); - }; + }, [level, selectedLevels, t]); return ( // ... rest of the render logic ); - }; + }, [rootOrganizations?.results, organizationQueries, selectedLevels, t]);
152-164
: Enhance accessibility for selected organization display.Consider adding ARIA labels and roles to improve accessibility:
- <div className="flex items-center gap-3 rounded-md border border-sky-100 bg-sky-50/50 p-2.5"> + <div + className="flex items-center gap-3 rounded-md border border-sky-100 bg-sky-50/50 p-2.5" + role="status" + aria-label={`Selected organization: ${selectedOrganization.name}`} + > <Building className="h-4 w-4 text-sky-600 flex-shrink-0" /> <div className="flex-1 min-w-0"> <p className="font-medium text-sm text-sky-900 truncate">
177-177
: Add newline at end of file.Add a newline at the end of the file to comply with ESLint rules.
} +
🧰 Tools
🪛 ESLint
[error] 177-177: Insert
⏎
(prettier/prettier)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/ui/autocomplete.tsx
(2 hunks)src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
(3 hunks)
🧰 Additional context used
🪛 ESLint
src/components/ui/autocomplete.tsx
[error] 120-120: Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
(prettier/prettier)
[error] 121-121: Replace ··
with ····
(prettier/prettier)
[error] 122-122: Insert ··
(prettier/prettier)
[error] 123-123: Replace ······
with ········
(prettier/prettier)
[error] 124-124: Insert ··
(prettier/prettier)
[error] 125-125: Insert ··
(prettier/prettier)
[error] 126-126: Insert ··
(prettier/prettier)
[error] 127-127: Insert ··
(prettier/prettier)
[error] 128-128: Insert ··
(prettier/prettier)
[error] 129-129: Insert ··
(prettier/prettier)
[error] 130-130: Replace ········
with ··········
(prettier/prettier)
[error] 131-131: Replace ········onClick={()·=>·setOpen(true)}
with ··········onClick={()·=>·setOpen(true)}⏎······
(prettier/prettier)
[error] 132-132: Insert ··
(prettier/prettier)
[error] 133-133: Insert ··
(prettier/prettier)
[error] 134-134: Insert ··
(prettier/prettier)
[error] 135-135: Replace ········
with ··········
(prettier/prettier)
[error] 136-136: Insert ··
(prettier/prettier)
[error] 137-137: Replace ····
with ······
(prettier/prettier)
[error] 138-138: Insert ··
(prettier/prettier)
[error] 139-139: Insert ··
(prettier/prettier)
[error] 140-140: Insert ··
(prettier/prettier)
[error] 141-141: Replace ····
with ······
(prettier/prettier)
[error] 142-142: Insert ····
(prettier/prettier)
[error] 143-144: Replace ⏎
with ····
(prettier/prettier)
[error] 145-145: Insert ····
(prettier/prettier)
[error] 146-146: Insert ··
(prettier/prettier)
[error] 147-147: Insert ⏎
(prettier/prettier)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
[error] 177-177: Insert ⏎
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
src/components/ui/autocomplete.tsx
[failure] 120-120:
Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
[failure] 121-121:
Replace ··
with ····
[failure] 122-122:
Insert ··
[failure] 123-123:
Replace ······
with ········
[failure] 124-124:
Insert ··
[failure] 125-125:
Insert ··
[failure] 126-126:
Insert ··
[failure] 127-127:
Insert ··
🪛 GitHub Check: lint
src/components/ui/autocomplete.tsx
[failure] 120-120:
Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
[failure] 121-121:
Replace ··
with ····
[failure] 122-122:
Insert ··
[failure] 123-123:
Replace ······
with ········
[failure] 124-124:
Insert ··
[failure] 125-125:
Insert ··
[failure] 126-126:
Insert ··
[failure] 127-127:
Insert ··
🪛 GitHub Actions: Lint Code Base
src/components/ui/autocomplete.tsx
[error] 3-3: Replace import·{·cn·}·from·"@/lib/utils";
with ⏎import·{·cn·}·from·"@/lib/utils";⏎
🔇 Additional comments (8)
src/components/ui/autocomplete.tsx (5)
58-58
: Maintain focus indicators for accessibility.Removing all focus indicators (outline, border, ring, shadow) may impact keyboard navigation accessibility.
120-120
: Good refactoring with selectedOption.Extracting the selected option logic into a variable improves code readability and reduces duplication.
🧰 Tools
🪛 ESLint
[error] 120-120: Replace
const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
[failure] 120-120:
Replaceconst·selectedOption·=·options.find((option)·=>·option.value·===·value);
with··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
🪛 GitHub Check: lint
[failure] 120-120:
Replaceconst·selectedOption·=·options.find((option)·=>·option.value·===·value);
with··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
19-19
: Verify mobile breakpoint implementation.The
useBreakpoints
hook is used with{ default: true, sm: false }
, which means mobile-first design. Ensure this aligns with your application's breakpoint strategy.Also applies to: 50-50
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Search for other useBreakpoints implementations to verify consistency rg "useBreakpoints.*default.*sm" -A 2Length of output: 483
Mobile breakpoint implementation verified.
The
useBreakpoints
hook is used consistently in bothsrc/components/ui/autocomplete.tsx
andsrc/components/Questionnaire/ValueSetSelect.tsx
with{ default: true, sm: false }
. This confirms that the mobile-first configuration is applied as intended.🧰 Tools
🪛 ESLint
[error] 19-19: Replace
import·useBreakpoints·from·"@/hooks/useBreakpoints";
with⏎import·useBreakpoints·from·"@/hooks/useBreakpoints";⏎
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
[failure] 19-19:
Replaceimport·useBreakpoints·from·"@/hooks/useBreakpoints";
with⏎import·useBreakpoints·from·"@/hooks/useBreakpoints";⏎
🪛 GitHub Check: lint
[failure] 19-19:
Replaceimport·useBreakpoints·from·"@/hooks/useBreakpoints";
with⏎import·useBreakpoints·from·"@/hooks/useBreakpoints";⏎
131-131
:⚠️ Potential issueFix desktop dropdown toggle behavior.
The desktop implementation has the same toggle issue where clicking doesn't properly toggle the dropdown state.
- onClick={() => setOpen(true)} + onClick={() => setOpen(!open)}Likely invalid or redundant comment.
🧰 Tools
🪛 ESLint
[error] 131-131: Replace
········onClick={()·=>·setOpen(true)}
with··········onClick={()·=>·setOpen(true)}⏎······
(prettier/prettier)
121-121
: Verify modal behavior and pointer events.Two potential issues to verify:
- Setting
modal={true}
on Popover might be too restrictive for a dropdown- The
pointer-events-auto
class might be unnecessary as popovers handle pointer events by defaultAlso applies to: 139-139
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Search for other Popover implementations to verify consistency rg "Popover.*modal.*true" -A 2 rg "PopoverContent.*pointer-events-auto" -A 2Length of output: 575
Verified Modal and Pointer Events Configuration
- The
modal={true}
prop is consistently used in bothsrc/components/ui/autocomplete.tsx
andsrc/components/Common/UserSelector.tsx
, indicating intentional behavior across similar dropdown components.- There is no evidence of an additional
pointer-events-auto
class being applied toPopoverContent
anywhere in the codebase, which reinforces that the default handling of pointer events is relied upon.🧰 Tools
🪛 ESLint
[error] 121-121: Replace
··
with····
(prettier/prettier)
🪛 GitHub Check: cypress-run (1)
[failure] 121-121:
Replace··
with····
🪛 GitHub Check: lint
[failure] 121-121:
Replace··
with····
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (3)
1-2
: LGTM! Import changes align with PR objectives.The addition of
useQueries
andBuilding
icon imports supports the enhanced dropdown functionality and UI improvements.
47-56
: Add error and loading states for organization queries.The queries implementation should handle error and loading states to provide better user feedback.
58-74
:⚠️ Potential issueFix dropdown state management issue.
Based on user feedback, the dropdown resets when clicked instead of showing options. This might be related to the level change handling. Consider preserving the dropdown state when the user clicks on a dropdown that already has a value selected.
✅ Verification successful
🌐 Web query:
What are the best practices for handling dropdown state in React to prevent unwanted resets?
Length of output: 6005
Address Dropdown State Persistence in handleLevelChange
- Prevent Unnecessary Resets: Before updating the selection state, check if the clicked dropdown’s value is already active. For example, if the organization corresponding to the clicked value is already selected, you can avoid reassigning state—which may inadvertently trigger a reset.
- Separate Dropdown Visibility from Selection: Consider managing the dropdown’s open/close state using its own state variable (e.g., using a dedicated
isDropdownOpen
managed viauseState
). This ensures that updating the selected value (or levels) doesn’t force the dropdown to close unexpectedly.- Controlled Component Approach: Ensure that the dropdown remains a controlled component with its value and visibility explicitly driven by state. This promotes predictable re-rendering and avoids unintentional resets caused by mismatched or reinitialized states.
- Event Handling Considerations: If external clicks or event propagation are affecting dropdown behavior, use techniques like
e.stopPropagation()
to prevent parent handlers from interfering with the dropdown’s state.Implementing these changes in the
handleLevelChange
function (and possibly related parts of the dropdown component) should help maintain the state of an already selected dropdown and prevent unwanted resets.
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
🔭 Outside diff range comments (3)
src/components/ui/autocomplete.tsx (3)
58-58
: Restore focus indicators for keyboard accessibility.Removing all focus indicators (outline, border, ring, shadow) impacts keyboard navigation accessibility.
Apply this diff to restore focus indicators while maintaining a clean look:
- className="outline-none border-none ring-0 shadow-none" + className="focus:ring-2 focus:ring-offset-2 focus:ring-primary border-none"
67-74
: Fix dropdown behavior when selecting the same value.The current implementation closes the dropdown even when selecting the same value, which might contribute to the reported issue where "dropdown closes when clicked with a value selected".
Apply this diff to improve the behavior:
- onChange(currentValue === value ? "" : currentValue); - setOpen(false); + if (currentValue === value) { + return; // Keep dropdown open when selecting same value + } + onChange(currentValue); + setOpen(false);
105-105
: Fix mobile dropdown toggle behavior.The onClick handler always sets open to true, which doesn't properly handle toggling the dropdown state.
Apply this diff to implement proper toggle behavior:
- onClick={() => setOpen(true)} + onClick={() => setOpen(!open)}
♻️ Duplicate comments (1)
src/components/ui/autocomplete.tsx (1)
131-131
:⚠️ Potential issueFix desktop dropdown toggle behavior.
The onClick handler always sets open to true, which doesn't properly handle toggling the dropdown state.
Apply this diff to implement proper toggle behavior:
- onClick={() => setOpen(true)} + onClick={() => setOpen(!open)}🧰 Tools
🪛 ESLint
[error] 131-131: Replace
········onClick={()·=>·setOpen(true)}
with··········onClick={()·=>·setOpen(true)}⏎······
(prettier/prettier)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/ui/autocomplete.tsx
(2 hunks)src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
(3 hunks)
🧰 Additional context used
🪛 ESLint
src/components/ui/autocomplete.tsx
[error] 120-120: Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
(prettier/prettier)
[error] 121-121: Replace ··
with ····
(prettier/prettier)
[error] 122-122: Insert ··
(prettier/prettier)
[error] 123-123: Replace ······
with ········
(prettier/prettier)
[error] 124-124: Insert ··
(prettier/prettier)
[error] 125-125: Insert ··
(prettier/prettier)
[error] 126-126: Insert ··
(prettier/prettier)
[error] 127-127: Insert ··
(prettier/prettier)
[error] 128-128: Insert ··
(prettier/prettier)
[error] 129-129: Insert ··
(prettier/prettier)
[error] 130-130: Replace ········
with ··········
(prettier/prettier)
[error] 131-131: Replace ········onClick={()·=>·setOpen(true)}
with ··········onClick={()·=>·setOpen(true)}⏎······
(prettier/prettier)
[error] 132-132: Insert ··
(prettier/prettier)
[error] 133-133: Insert ··
(prettier/prettier)
[error] 134-134: Insert ··
(prettier/prettier)
[error] 135-135: Replace ········
with ··········
(prettier/prettier)
[error] 136-136: Insert ··
(prettier/prettier)
[error] 137-137: Replace ····
with ······
(prettier/prettier)
[error] 138-138: Insert ··
(prettier/prettier)
[error] 139-139: Insert ··
(prettier/prettier)
[error] 140-140: Insert ··
(prettier/prettier)
[error] 141-141: Replace ····
with ······
(prettier/prettier)
[error] 142-142: Insert ····
(prettier/prettier)
[error] 143-144: Replace ⏎
with ····
(prettier/prettier)
[error] 145-145: Insert ····
(prettier/prettier)
[error] 146-146: Insert ··
(prettier/prettier)
[error] 147-147: Insert ⏎
(prettier/prettier)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
[error] 177-177: Insert ⏎
(prettier/prettier)
🪛 GitHub Check: lint
src/components/ui/autocomplete.tsx
[failure] 120-120:
Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
[failure] 121-121:
Replace ··
with ····
[failure] 122-122:
Insert ··
[failure] 123-123:
Replace ······
with ········
[failure] 124-124:
Insert ··
[failure] 125-125:
Insert ··
[failure] 126-126:
Insert ··
[failure] 127-127:
Insert ··
🪛 GitHub Check: cypress-run (1)
src/components/ui/autocomplete.tsx
[failure] 120-120:
Replace const·selectedOption·=·options.find((option)·=>·option.value·===·value);
with ··const·selectedOption·=·options.find((option)·=>·option.value·===·value);⏎·
[failure] 121-121:
Replace ··
with ····
[failure] 122-122:
Insert ··
[failure] 123-123:
Replace ······
with ········
[failure] 124-124:
Insert ··
[failure] 125-125:
Insert ··
[failure] 126-126:
Insert ··
[failure] 127-127:
Insert ··
🪛 GitHub Actions: Lint Code Base
src/components/ui/autocomplete.tsx
[error] 3-3: Replace import·{·cn·}·from·"@/lib/utils";
with ⏎import·{·cn·}·from·"@/lib/utils";⏎
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: Redirect rules - care-ohc
- GitHub Check: Header rules - care-ohc
- GitHub Check: Pages changed - care-ohc
- GitHub Check: OSSAR-Scan
- GitHub Check: CodeQL-Build
🔇 Additional comments (2)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (2)
152-164
: LGTM! Well-implemented organization display.The implementation nicely displays the selected organization with a blue building icon and appropriate styling, meeting the PR objectives.
47-56
: 🛠️ Refactor suggestionAdd loading and error states for organization queries.
The queries implementation doesn't provide feedback during loading or when errors occur.
Add loading and error states to improve user experience:
const organizationQueries = useQueries({ queries: selectedLevels.map((level, _index) => ({ queryKey: ["organizations", level.id], queryFn: query(routes.facilityOrganization.list, { pathParams: { facilityId }, queryParams: { parent: level.id }, }), enabled: !!level.id, })), }); + +// Add loading and error handling in renderOrganizationLevel +const isLoading = level > 0 && organizationQueries[level - 1].isLoading; +const error = level > 0 && organizationQueries[level - 1].error; + +if (isLoading) return <div>Loading...</div>; +if (error) return <div>Error loading organizations</div>;Likely invalid or redundant comment.
className="cursor-pointer p-1 hover:bg-gray-100 rounded-sm opacity-0 group-hover:opacity-100 transition-opacity" | ||
onClick={() => handleEdit(level)} | ||
> | ||
<CareIcon icon="l-pen" className="h-4 w-4 text-gray-500" /> |
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.
Replace edit pencil with dropdown arrow per PR objectives.
The PR objectives mention replacing the edit pencil with a dropdown arrow, but the implementation still uses the pencil icon.
Apply this diff to align with PR objectives:
- <CareIcon icon="l-pen" className="h-4 w-4 text-gray-500" />
+ <CareIcon icon="l-chevron-down" className="h-4 w-4 text-gray-500" />
📝 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.
<CareIcon icon="l-pen" className="h-4 w-4 text-gray-500" /> | |
<CareIcon icon="l-chevron-down" className="h-4 w-4 text-gray-500" /> |
@nihal467 @rithviknishad @Jacobjeevan Fixed merge conflicts |
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: 0
♻️ Duplicate comments (3)
src/components/ui/autocomplete.tsx (1)
141-141
:⚠️ Potential issueFix dropdown toggle behavior.
The current onClick implementation doesn't properly handle the toggle case, which explains the reported issue where "dropdown closes when clicked with a value selected".
Apply this fix:
- onClick={() => setOpen(true)} + onClick={() => setOpen(!open)}src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (2)
50-59
: 🛠️ Refactor suggestionAdd loading and error states for organization queries.
The queries lack feedback for loading and error states.
Consider adding loading indicators and error messages for each query:
const organizationQueries = useQueries({ queries: selectedLevels.map((level, _index) => ({ queryKey: ["organizations", level.id], queryFn: query(routes.facilityOrganization.list, { pathParams: { facilityId }, queryParams: { parent: level.id }, }), enabled: !!level.id, + retry: false, })), });
Then handle the states in renderOrganizationLevel:
if (level > 0 && organizationQueries[level - 1].isLoading) { return <div>Loading...</div>; } if (level > 0 && organizationQueries[level - 1].isError) { return <div>Error loading organizations</div>; }
141-141
:⚠️ Potential issueReplace edit pencil with dropdown arrow per PR objectives.
The PR objectives mention replacing the edit pencil with a dropdown arrow.
Apply this change:
- <CareIcon icon="l-pen" className="h-4 w-4 text-gray-500" /> + <CareIcon icon="l-chevron-down" className="h-4 w-4 text-gray-500" />
🧹 Nitpick comments (1)
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (1)
171-178
: Consider adding aria-labels for accessibility.The nested organization levels could benefit from ARIA labels for better screen reader support.
Add descriptive labels:
- <div key={org.id}>{renderOrganizationLevel(index)}</div> + <div + key={org.id} + aria-label={`Organization level ${index + 1}: ${org.name}`} + > + {renderOrganizationLevel(index)} + </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/ui/autocomplete.tsx
(2 hunks)src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx
(3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: cypress-run (1)
🔇 Additional comments (4)
src/components/ui/autocomplete.tsx (3)
64-64
: Remove focus-related classes to maintain accessibility.The removal of focus indicators impacts keyboard navigation accessibility.
Apply this fix to maintain accessibility standards:
- className="outline-none border-none ring-0 shadow-none" + className="focus:ring-2 focus:ring-offset-2 focus:ring-primary"
78-79
: Optimize onChange handler to prevent unnecessary updates.The current implementation might cause unnecessary re-renders.
Apply this optimization:
- onChange(currentValue === value ? "" : currentValue); - setOpen(false); + const newValue = currentValue === value ? "" : currentValue; + if (newValue !== value) { + onChange(newValue); + setOpen(false); + }
128-129
: LGTM! Good refactoring of selectedOption logic.The introduction of
selectedOption
variable improves code readability and reduces duplicate logic.Also applies to: 134-134, 143-144
src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx (1)
157-169
: LGTM! Nice UI improvements with the Building icon.The addition of the Building icon and improved layout for the selected organization enhances visibility and user experience, aligning with PR objectives.
LGTM |
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Jeffrin2005 Your efforts have helped advance digital healthcare and TeleICU systems. 🚀 Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! 🙌 |
Proposed Changes
Fixes Enhance Facility Organization Dropdown Experience #10060
Changed from edit pencil icon to dropdown arrow
Added building icon only for the main selected organization with blue color
v23.mp4
@ohcnetwork/care-fe-code-reviewers
Merge Checklist
Summary by CodeRabbit