WEB-4460 - Setup TIDE Dashboard - #1976
Conversation
This reverts commit ed12408.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (4)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 Walkthrough<review_stack_artifact_context> WalkthroughThis PR introduces a new Tide Dashboard V2 feature comprising Redux slices for dashboard/filter state, an RTK Query patient-fetching endpoint with CGM exclusion logic, filter/category UI components, table cell renderers, pagination, and localStorage-backed filter persistence. It also wires the new dashboard into clinicworkspace tabs and refactors ClinicPatients pagination/filter UI to shared components. ChangesTide Dashboard V2
ClinicPatients pagination and filter UI refactor
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant TideDashboardV2
participant Redux
participant tideDashboardApi
participant RTKQueryApi
User->>TideDashboardV2: select category/tag/site filter
TideDashboardV2->>Redux: dispatch setCategory / setPatientTagsFilter / setClinicSitesFilter / setOffset(0)
Redux-->>TideDashboardV2: updated state
TideDashboardV2->>tideDashboardApi: useGetTideDashboardPatientsQuery(params)
tideDashboardApi->>RTKQueryApi: GET /clinics/:clinicId/patients
RTKQueryApi-->>tideDashboardApi: patients + total
tideDashboardApi-->>TideDashboardV2: table data
TideDashboardV2->>User: render table, pagination, and empty state
Related PRs: None found. Suggested labels: enhancement, tide-dashboard Suggested reviewers: None determined. 🐰 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| case threshold.startsWith('>='): return threshold.replace('>=', '<'); | ||
| case threshold.startsWith('<='): return threshold.replace('<=', '>'); | ||
| case threshold.startsWith('>'): return threshold.replace('>', '<='); | ||
| case threshold.startsWith('<'): return threshold.replace('<', '>='); |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/pages/clinicworkspace/clinicworkspace.js (1)
76-86: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winStale
selectedTabwhentabIndiceschanges after mount.
tabIndicesis now derived dynamically fromtabs, which depends onuseFlags()and clinic entitlements — both of which can resolve asynchronously after the initial render, shifting tab positions (e.g., the TIDE_DASHBOARD tab appearing once flags load). The existinguseEffect(lines 82-86) only re-syncsselectedTabwhen the URLtabparam changes, not whentabIndicesitself changes, soselectedTabcan point at the wrong tab index once flags resolve, and the panel rendering at lines 147-159 (which usesselectedTab === tabIndices[TAB.X]) will show/hide the wrong content. As per coding guidelines, "respectreact-hooks/exhaustive-deps".🐛 Proposed fix
useEffect(() => { if (tab && tab in tabIndices && tabIndices[tab] !== selectedTab) { setSelectedTab(tabIndices[tab]); } - }, [tab]); + }, [tab, tabIndices]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/clinicworkspace.js` around lines 76 - 86, The `selectedTab` state can become stale when `tabIndices` changes after async flags/entitlements load, because the sync effect only watches `tab`. Update the `useEffect` in `ClinicWorkspace` to re-derive `selectedTab` whenever `tabIndices` changes (and keep the URL `tab` param in sync), and include the missing hook dependencies so `react-hooks/exhaustive-deps` is satisfied. Use the `tabs`, `tabIndices`, `selectedTab`, and `setSelectedTab` logic to locate the fix, and ensure the rendered tab panels continue to use the current index mapping.Source: Coding guidelines
🧹 Nitpick comments (21)
app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js (1)
3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider extracting
CATEGORYout of a component file.
CATEGORYis imported from./FilterByCategory, a UI component. Both this slice andtideDashboardApi.jsdepend on it, coupling Redux/data layers to a presentational component and creating circular-import risk ifFilterByCategoryever needs slice actions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js` at line 3, `CATEGORY` is currently being pulled from the `FilterByCategory` component, which couples the slice to UI code and risks circular imports. Extract `CATEGORY` into a shared non-component module (for example a constants file used by both `tideDashboardSlice` and `tideDashboardApi`) and update the imports in `tideDashboardSlice` and any other consumers to reference that shared symbol instead of the component.app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js (2)
96-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove commented-out prop wiring or implement it.
sx,onSort,order,orderBy,onClickRoware left commented out. Either wire these up now or drop the dead code to keep the component clean.🧹 Proposed cleanup
- // sx={tableStyle} - // onSort={handleSortChange} - // order={sort?.substring(0, 1) === '+' ? 'asc' : 'desc'} - // orderBy={sort?.substring(1)} - // onClickRow={handleClickPatient}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 96 - 100, The TideDashboardV2 component still has dead commented-out prop wiring for the table, which should be cleaned up or restored. In TideDashboardV2.js, either pass the intended props through to the table/component using the existing handlers and state like handleSortChange, sort, and handleClickPatient, or remove the commented lines entirely if they are not needed. Keep the component definition clean by resolving the commented `sx`, `onSort`, `order`, `orderBy`, and `onClickRow` wiring around the table usage.
81-93: 🎯 Functional Correctness | 🔵 TrivialSeveral table columns are non-functional placeholders.
Flag,Avg Glucose,% TIR,% Time in Range,% Change in TIR,GMI,CGM Use, and the trailing// Morecolumn all have an emptyfieldand norender, so they'll always render blank cells. If this is deliberate scaffolding for a later PR in the stack, consider tracking it explicitly (e.g., TODO) so it isn't missed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 81 - 93, The TideDashboardV2 table defines several non-functional placeholder columns with empty field values and no renderers, so they will always display blank cells. Update the columns in TideDashboardV2 to either wire each one to real data/render logic using the relevant table row fields or explicitly mark them as intentional scaffolding with a clear TODO/comment so they are not mistaken for finished UI, including the trailing More column.app/redux/store/configureStore.dev.js (1)
112-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract duplicated persistence logic; drop leftover dead comment.
Line 112 is a stray leftover comment from an earlier draft. Also, this entire subscribe/persist block (112-124) is duplicated almost verbatim in
configureStore.prod.js(lines 68-80). Extracting both into a small shared helper (e.g.persistBlipState(store)inlocalStorage.js) would remove the dead comment and prevent the dev/prod persistence logic from drifting apart over time.♻️ Proposed refactor sketch
- // tideDashboardFilters: store.getState().blip?.tideDashboardFilters, - - store.subscribe(throttle(() => { - const selectedClinicId = store.getState().blip?.selectedClinicId; - const loggedInUserId = store.getState().blip?.loggedInUserId; - - saveLocalState({ selectedClinicId }); - - if (loggedInUserId && selectedClinicId) { - const tideDashboardFiltersKey = getTideDashboardFiltersKey(loggedInUserId, selectedClinicId); - - saveLocalState(store.getState().blip?.tideDashboardFilters, tideDashboardFiltersKey); - } - }, 1000)); + store.subscribe(throttle(() => persistBlipState(store), 1000));// localStorage.js export const persistBlipState = (store) => { const selectedClinicId = store.getState().blip?.selectedClinicId; const loggedInUserId = store.getState().blip?.loggedInUserId; saveLocalState({ selectedClinicId }); if (loggedInUserId && selectedClinicId) { saveLocalState( store.getState().blip?.tideDashboardFilters, getTideDashboardFiltersKey(loggedInUserId, selectedClinicId) ); } };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/redux/store/configureStore.dev.js` around lines 112 - 125, Remove the stray leftover comment in configureStore.dev.js and extract the duplicated subscribe/throttled persistence logic into a shared helper so dev and prod stay in sync. Create a small function such as persistBlipState(store) alongside the existing localStorage helpers, and have both configureStore.dev.js and configureStore.prod.js call it from their store.subscribe(throttle(...)) blocks. Keep the helper responsible for reading selectedClinicId, loggedInUserId, saving selectedClinicId, and persisting tideDashboardFilters via getTideDashboardFiltersKey.app/pages/clinicworkspace/components/TagListCell.js (1)
5-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMissing PropTypes on
TagListCell.As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/TagListCell.js` around lines 5 - 14, Add PropTypes for TagListCell’s props to satisfy the component prop validation guideline. Update the TagListCell component to declare the expected shape for the patient prop, including its tags field, using the same propTypes pattern used elsewhere in the codebase. Keep the validation рядом with TagListCell so the prop contract is explicit and easy to maintain.Source: Coding guidelines
app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js (2)
1-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueImport order deviates from guideline groups.
Redux (
react-redux) should precede third-party libs, and third-party (@tidepool/viz) should be grouped together, before theme-ui and local imports.As per coding guidelines, "Group imports in the required order with blank lines between groups: React, PropTypes, Redux, third-party libraries, Lodash specific imports, theme-ui, then local imports."
♻️ Suggested import order
import React from 'react'; -import { useTranslation } from 'react-i18next'; import { useSelector, useDispatch } from 'react-redux'; + +import { useTranslation } from 'react-i18next'; +import { colors as vizColors } from '`@tidepool/viz`'; + +import { Box } from 'theme-ui'; + import { CategorySegmentedControl, Segment } from '../components/CategorySegmentedControl'; import { setCategory, setOffset } from './tideDashboardSlice'; -import { colors as vizColors } from '`@tidepool/viz`'; -import { Box } from 'theme-ui';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js` around lines 1 - 7, The import block in FilterByCategory.js is out of the required grouping order: keep React first, then Redux imports from react-redux, then third-party libraries like `@tidepool/viz`, then theme-ui, and finally local imports such as CategorySegmentedControl and tideDashboardSlice. Reorder the existing imports in that file to match the project’s import grouping guideline and separate each group with blank lines.Source: Coding guidelines
22-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMissing PropTypes on
Indicator.
Indicatoraccepts acolorprop but has no PropTypes definition.As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js` around lines 22 - 28, The Indicator component currently accepts a color prop but does not define PropTypes, so add a PropTypes declaration for Indicator’s color property alongside the component definition in FilterByCategory.js. Use the Indicator symbol to locate the component and ensure the prop is marked as required or typed according to the existing component prop conventions in this file.Source: Coding guidelines
app/pages/clinicworkspace/TideDashboardV2/Cells.js (1)
5-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMissing PropTypes on
PatientCell.
PatientCellaccepts apatientprop without PropTypes.As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/Cells.js` around lines 5 - 15, PatientCell is missing PropTypes for its patient prop, so add prop type validation for the component. Update PatientCell in Cells.js to define its expected props shape using PropTypes, including the patient object and the fields it reads (fullName, birthDate, mrn), and make sure the PropTypes are attached to PatientCell alongside the existing component definition.Source: Coding guidelines
app/pages/clinicworkspace/components/CategorySegmentedControl.js (2)
20-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd ARIA semantics for the interactive
Segment.
Segmenthandles keyboard activation but has noroleoraria-pressed, so assistive tech won't announce it as a toggle/tab control or expose its selected state.♿ Suggested fix
<Flex onClick={onClick} onKeyDown={(evt) => { if (evt.key === 'Enter' || evt.key === ' ') { onClick(); } }} tabIndex="0" + role="button" + aria-pressed={selected} px={4}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js` around lines 20 - 52, The interactive Segment component supports click and keyboard activation but is missing accessible semantics. Update the Segment component to expose the correct ARIA role and selected state by adding a suitable role and an aria-pressed or equivalent selected-state attribute tied to the selected prop. Keep the keyboard and click behavior in Segment consistent with the new semantics so assistive technologies can announce it properly.
6-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMissing PropTypes on
CategorySegmentedControlandSegment.Neither component declares PropTypes for its props (
children,selected,onClick).As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js` around lines 6 - 18, Add PropTypes declarations for the components in CategorySegmentedControl.js so all props are explicitly validated. Update CategorySegmentedControl to declare children, and add PropTypes for Segment to cover selected and onClick (and any other props it receives) using the component names as anchors so the definitions stay with the exports.Source: Coding guidelines
app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js (1)
1-8: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueImport grouping deviates from guideline order.
Redux, local, and third-party imports are interleaved rather than grouped as React → Redux → third-party → theme-ui → local.
As per coding guidelines, "Group imports in the required order with blank lines between groups: React, PropTypes, Redux, third-party libraries, Lodash specific imports, theme-ui, then local imports."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js` around lines 1 - 8, The imports in TableCategoryHeader are not grouped in the required order, with Redux, third-party, theme-ui, and local imports mixed together. Reorder the imports in the module so they follow the project’s grouping convention: React first, then Redux, then third-party libraries, then theme-ui, and finally local imports, with blank lines between each group. Use the existing symbols like useSelector, useTranslation, Box, Text, vizColors, vizUtils, utils, and MGDL_UNITS to keep the imports in the correct grouped sections.Source: Coding guidelines
app/pages/clinicworkspace/components/PaginationControls.js (1)
4-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for component props.
♻️ Proposed fix
import React from 'react'; +import PropTypes from 'prop-types'; import Pagination from '../../../components/elements/Pagination'; const PaginationControls = ({ total = 0, limit, offset, onOffsetChange }) => { ... }; +PaginationControls.propTypes = { + total: PropTypes.number, + limit: PropTypes.number.isRequired, + offset: PropTypes.number.isRequired, + onOffsetChange: PropTypes.func.isRequired, +}; export default PaginationControls;As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/PaginationControls.js` around lines 4 - 28, Add PropTypes for PaginationControls props to match the coding guidelines. Define prop validation for total, limit, offset, and onOffsetChange on the PaginationControls component so the expected types are explicit and any missing/invalid props are caught during development.Source: Coding guidelines
app/pages/clinicworkspace/components/ResetFilters.js (1)
6-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for component props.
hiddenandonClickprops aren't typed.♻️ Proposed fix
import React from 'react'; +import PropTypes from 'prop-types'; import noop from 'lodash/noop'; import { useTranslation } from 'react-i18next'; import Button from '../../../components/elements/Button'; const ResetFilters = ({ hidden = false, onClick = noop }) => { ... }; +ResetFilters.propTypes = { + hidden: PropTypes.bool, + onClick: PropTypes.func, +}; export default ResetFilters;As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/ResetFilters.js` around lines 6 - 24, The ResetFilters component is missing PropTypes for its props, so add prop type definitions for hidden and onClick in the ResetFilters component export. Use the component name ResetFilters to locate the function, and define hidden as a boolean and onClick as a function, matching the existing default props behavior.Source: Coding guidelines
app/pages/clinicworkspace/components/SitesFilterDropdown.js (1)
35-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for component props.
Neither
DropdownContentnorSitesFilterDropdowndefine PropTypes for their props.As per coding guidelines, "Define PropTypes for all component props."
Also applies to: 158-161
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js` around lines 35 - 39, Add PropTypes definitions for both DropdownContent and SitesFilterDropdown so all expected props are explicitly validated. Update the component declarations to include prop type checks for handlers and data props such as onClose, onChange, clinicSites, and any props accepted by SitesFilterDropdown, using the existing component names to place the new propTypes alongside their definitions.Source: Coding guidelines
app/pages/clinicworkspace/components/TagFilterDropdown.js (3)
158-161: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for
onChange/patientTags.As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` around lines 158 - 161, The TagFilterDropdown component currently defines default values for onChange and patientTags but does not declare PropTypes for its props. Add PropTypes for TagFilterDropdown so both onChange and patientTags are explicitly validated, using the TagFilterDropdown function/component name to place the prop type definitions alongside the component export.Source: Coding guidelines
30-31: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win
trackMetric/prefixPopHealthMetricare no-op stubs — analytics calls silently do nothing.
trackMetricis defined as() => noop, so every call liketrackMetric(prefixPopHealthMetric('...'), {...})(lines 136, 146, 180, 221) just returns thenoopfunction without invoking any tracking side effect. If this is intentional scaffolding for the "Setup" PR, consider wiring these through actual tracking (e.g. as props threaded from the parent, similar to howClinicPatients.jspassestrackMetricintoMoreMenu/PatientTags), otherwise this component's analytics instrumentation is effectively dead code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` around lines 30 - 31, The analytics helpers in TagFilterDropdown are currently stubs, so calls to trackMetric(prefixPopHealthMetric(...), ...) do nothing. Replace the noop definitions with real tracking plumbing by accepting these functions as props or otherwise wiring them from the parent, and update TagFilterDropdown’s callers to pass the actual metric functions so the existing trackMetric calls produce side effects instead of silently returning noop.
33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract
SPECIAL_FILTER_STATESinto a shared module
TagFilterDropdown.jsandSitesFilterDropdown.jsboth depend onClinicPatients.jsonly for this constant. Moving it out of the page component keeps reusable dropdowns decoupled and avoids a future circular dependency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` at line 33, SPECIAL_FILTER_STATES is being imported from ClinicPatients.js just to support TagFilterDropdown, which couples reusable dropdowns to the page component. Move SPECIAL_FILTER_STATES into a shared module and update TagFilterDropdown and SitesFilterDropdown to import it from there instead of ClinicPatients. Keep the constant in a standalone location that both dropdown components can reference without depending on the page.app/pages/clinicworkspace/components/PatientCount.js (2)
9-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant
total === 0check.Line 9 already returns
nullwhentotal === 0, so the ternary on line 11 always resolves tooffset + 1.♻️ Proposed simplification
- const start = total === 0 ? 0 : offset + 1; + const start = offset + 1;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/PatientCount.js` around lines 9 - 11, In PatientCount, remove the redundant total === 0 branch from the start calculation because the early return already handles that case; simplify the logic so the start value is derived directly from offset in the component’s render path, keeping the existing null return for zero totals.
6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for
total,offset,limit.As per coding guidelines, "Define PropTypes for all component props."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/PatientCount.js` at line 6, PatientCount is missing PropTypes for its component props, so add prop type validation for total, offset, and limit on the PatientCount component. Update the PatientCount definition to include a PropTypes declaration that matches the existing default values and optional limit prop, so the component conforms to the project’s prop-type guidelines.Source: Coding guidelines
app/pages/clinicworkspace/components/ActiveFilterCount.js (1)
10-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd PropTypes for
count.Component prop
counthas no PropTypes definition.As per coding guidelines, "Define PropTypes for all component props."
♻️ Proposed fix
import React from 'react'; +import PropTypes from 'prop-types'; import { Flex, Text } from 'theme-ui';export default ActiveFilterCount; + +ActiveFilterCount.propTypes = { + count: PropTypes.number, +};🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/pages/clinicworkspace/components/ActiveFilterCount.js` around lines 10 - 46, Add PropTypes for the ActiveFilterCount component’s count prop, since it is currently undocumented by runtime prop validation. Update ActiveFilterCount to declare count with an appropriate numeric PropTypes definition alongside the existing useTranslation logic and JSX, so the component follows the project guideline that all component props must have PropTypes.Source: Coding guidelines
app/components/elements/Table.js (1)
230-238: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
data-testidcan collide across columns with emptyfield.Several dashboard table columns use
field: ''(seeTideDashboardV2.jscolumn definitions), sodata-testid={\${id}-row-${rowIndex}-${col.field}`}` will produce duplicate/ambiguous test ids within the same row, weakening the value of these new selectors for RTL/Jest tests.As per coding guidelines for `**/*.{js,jsx,ts,tsx}` files, tests should use stable/descriptive selectors, and `__tests__/**/*.js` guidelines call for `userEvent`-driven interaction testing that benefits from unambiguous test ids.♻️ Proposed fix using column index for uniqueness
{map(columns, (col, index) => ( <TableCell id={`${id}-row-${rowIndex}-${col.field}`} key={`${id}-row-${rowIndex}-${col.field}`} - data-testid={`${id}-row-${rowIndex}-${col.field}`} + data-testid={`${id}-row-${rowIndex}-${col.field || index}`}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/components/elements/Table.js` around lines 230 - 238, The row cell test ids in Table.js can collide when a column has an empty field value, so update the Table rendering logic to make the `data-testid` for each `TableCell` unique per column. Use the existing `map(columns, (col, index) => ...)` loop and incorporate the column index (or another stable unique column identifier) into the row/cell test id generation alongside `id` and `rowIndex`, so selectors remain unambiguous even when `col.field` is empty.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js`:
- Line 33: Move SPECIAL_FILTER_STATES out of ClinicPatients.js and into a shared
constants module so SitesFilterDropdown stays independent of a page-level
import. Update SitesFilterDropdown and ClinicPatients to import the constant
from the new shared location, and make sure any other consumers such as
TideDashboardV2/FilterBySites use the same shared source to avoid circular
dependencies.
In `@app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js`:
- Line 33: Resetting filters currently leaves pagination untouched, so the
dashboard can stay on a non-zero offset after filters are cleared. Update
handleResetFilters to also reset the pagination state by setting offset back to
0 along with dispatching resetTideDashboardFilters(), using the existing
dashboard state/actions around TideDashboardV2.
In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js`:
- Around line 40-58: The TideDashboardV2 component returns null while
useGetTideDashboardPatientsQuery is still resolving because it only checks data,
which leaves a blank area on navigation. Update TideDashboardV2.js to use the
query’s loading state (for example from useGetTideDashboardPatientsQuery) and
render an appropriate skeleton/spinner until the request finishes, then fall
through to the existing tableData/total rendering once data is available.
In `@app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js`:
- Around line 1-4: The import ordering in usePruneInvalidFilters is incorrect
because the Lodash import for keyBy is placed after the local
tideDashboardFiltersSlice import. Reorder the imports to follow the required
grouping in this file: React, Redux, third-party, Lodash, then local, keeping
keyBy before ./tideDashboardFiltersSlice while preserving the existing
useEffect, useDispatch, useSelector, and
setPatientTagsFilter/setClinicSitesFilter references.
- Line 10: The selector in usePruneInvalidFilters is reading the wrong shape
from state, so patientTags and clinicSites become undefined and both pruning
effects never run. Update the useSelector call to select the full
tideDashboardFilters slice (or the actual arrays directly) instead of
destructuring from state.blip.tideDashboardFilters.patientTags, then verify the
existing patientTags/clinicSites effects in usePruneInvalidFilters still receive
arrays and can prune stale IDs as intended.
---
Outside diff comments:
In `@app/pages/clinicworkspace/clinicworkspace.js`:
- Around line 76-86: The `selectedTab` state can become stale when `tabIndices`
changes after async flags/entitlements load, because the sync effect only
watches `tab`. Update the `useEffect` in `ClinicWorkspace` to re-derive
`selectedTab` whenever `tabIndices` changes (and keep the URL `tab` param in
sync), and include the missing hook dependencies so
`react-hooks/exhaustive-deps` is satisfied. Use the `tabs`, `tabIndices`,
`selectedTab`, and `setSelectedTab` logic to locate the fix, and ensure the
rendered tab panels continue to use the current index mapping.
---
Nitpick comments:
In `@app/components/elements/Table.js`:
- Around line 230-238: The row cell test ids in Table.js can collide when a
column has an empty field value, so update the Table rendering logic to make the
`data-testid` for each `TableCell` unique per column. Use the existing
`map(columns, (col, index) => ...)` loop and incorporate the column index (or
another stable unique column identifier) into the row/cell test id generation
alongside `id` and `rowIndex`, so selectors remain unambiguous even when
`col.field` is empty.
In `@app/pages/clinicworkspace/components/ActiveFilterCount.js`:
- Around line 10-46: Add PropTypes for the ActiveFilterCount component’s count
prop, since it is currently undocumented by runtime prop validation. Update
ActiveFilterCount to declare count with an appropriate numeric PropTypes
definition alongside the existing useTranslation logic and JSX, so the component
follows the project guideline that all component props must have PropTypes.
In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js`:
- Around line 20-52: The interactive Segment component supports click and
keyboard activation but is missing accessible semantics. Update the Segment
component to expose the correct ARIA role and selected state by adding a
suitable role and an aria-pressed or equivalent selected-state attribute tied to
the selected prop. Keep the keyboard and click behavior in Segment consistent
with the new semantics so assistive technologies can announce it properly.
- Around line 6-18: Add PropTypes declarations for the components in
CategorySegmentedControl.js so all props are explicitly validated. Update
CategorySegmentedControl to declare children, and add PropTypes for Segment to
cover selected and onClick (and any other props it receives) using the component
names as anchors so the definitions stay with the exports.
In `@app/pages/clinicworkspace/components/PaginationControls.js`:
- Around line 4-28: Add PropTypes for PaginationControls props to match the
coding guidelines. Define prop validation for total, limit, offset, and
onOffsetChange on the PaginationControls component so the expected types are
explicit and any missing/invalid props are caught during development.
In `@app/pages/clinicworkspace/components/PatientCount.js`:
- Around line 9-11: In PatientCount, remove the redundant total === 0 branch
from the start calculation because the early return already handles that case;
simplify the logic so the start value is derived directly from offset in the
component’s render path, keeping the existing null return for zero totals.
- Line 6: PatientCount is missing PropTypes for its component props, so add prop
type validation for total, offset, and limit on the PatientCount component.
Update the PatientCount definition to include a PropTypes declaration that
matches the existing default values and optional limit prop, so the component
conforms to the project’s prop-type guidelines.
In `@app/pages/clinicworkspace/components/ResetFilters.js`:
- Around line 6-24: The ResetFilters component is missing PropTypes for its
props, so add prop type definitions for hidden and onClick in the ResetFilters
component export. Use the component name ResetFilters to locate the function,
and define hidden as a boolean and onClick as a function, matching the existing
default props behavior.
In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js`:
- Around line 35-39: Add PropTypes definitions for both DropdownContent and
SitesFilterDropdown so all expected props are explicitly validated. Update the
component declarations to include prop type checks for handlers and data props
such as onClose, onChange, clinicSites, and any props accepted by
SitesFilterDropdown, using the existing component names to place the new
propTypes alongside their definitions.
In `@app/pages/clinicworkspace/components/TagFilterDropdown.js`:
- Around line 158-161: The TagFilterDropdown component currently defines default
values for onChange and patientTags but does not declare PropTypes for its
props. Add PropTypes for TagFilterDropdown so both onChange and patientTags are
explicitly validated, using the TagFilterDropdown function/component name to
place the prop type definitions alongside the component export.
- Around line 30-31: The analytics helpers in TagFilterDropdown are currently
stubs, so calls to trackMetric(prefixPopHealthMetric(...), ...) do nothing.
Replace the noop definitions with real tracking plumbing by accepting these
functions as props or otherwise wiring them from the parent, and update
TagFilterDropdown’s callers to pass the actual metric functions so the existing
trackMetric calls produce side effects instead of silently returning noop.
- Line 33: SPECIAL_FILTER_STATES is being imported from ClinicPatients.js just
to support TagFilterDropdown, which couples reusable dropdowns to the page
component. Move SPECIAL_FILTER_STATES into a shared module and update
TagFilterDropdown and SitesFilterDropdown to import it from there instead of
ClinicPatients. Keep the constant in a standalone location that both dropdown
components can reference without depending on the page.
In `@app/pages/clinicworkspace/components/TagListCell.js`:
- Around line 5-14: Add PropTypes for TagListCell’s props to satisfy the
component prop validation guideline. Update the TagListCell component to declare
the expected shape for the patient prop, including its tags field, using the
same propTypes pattern used elsewhere in the codebase. Keep the validation рядом
with TagListCell so the prop contract is explicit and easy to maintain.
In `@app/pages/clinicworkspace/TideDashboardV2/Cells.js`:
- Around line 5-15: PatientCell is missing PropTypes for its patient prop, so
add prop type validation for the component. Update PatientCell in Cells.js to
define its expected props shape using PropTypes, including the patient object
and the fields it reads (fullName, birthDate, mrn), and make sure the PropTypes
are attached to PatientCell alongside the existing component definition.
In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js`:
- Around line 1-7: The import block in FilterByCategory.js is out of the
required grouping order: keep React first, then Redux imports from react-redux,
then third-party libraries like `@tidepool/viz`, then theme-ui, and finally local
imports such as CategorySegmentedControl and tideDashboardSlice. Reorder the
existing imports in that file to match the project’s import grouping guideline
and separate each group with blank lines.
- Around line 22-28: The Indicator component currently accepts a color prop but
does not define PropTypes, so add a PropTypes declaration for Indicator’s color
property alongside the component definition in FilterByCategory.js. Use the
Indicator symbol to locate the component and ensure the prop is marked as
required or typed according to the existing component prop conventions in this
file.
In `@app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js`:
- Around line 1-8: The imports in TableCategoryHeader are not grouped in the
required order, with Redux, third-party, theme-ui, and local imports mixed
together. Reorder the imports in the module so they follow the project’s
grouping convention: React first, then Redux, then third-party libraries, then
theme-ui, and finally local imports, with blank lines between each group. Use
the existing symbols like useSelector, useTranslation, Box, Text, vizColors,
vizUtils, utils, and MGDL_UNITS to keep the imports in the correct grouped
sections.
In `@app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js`:
- Line 3: `CATEGORY` is currently being pulled from the `FilterByCategory`
component, which couples the slice to UI code and risks circular imports.
Extract `CATEGORY` into a shared non-component module (for example a constants
file used by both `tideDashboardSlice` and `tideDashboardApi`) and update the
imports in `tideDashboardSlice` and any other consumers to reference that shared
symbol instead of the component.
In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js`:
- Around line 96-100: The TideDashboardV2 component still has dead commented-out
prop wiring for the table, which should be cleaned up or restored. In
TideDashboardV2.js, either pass the intended props through to the
table/component using the existing handlers and state like handleSortChange,
sort, and handleClickPatient, or remove the commented lines entirely if they are
not needed. Keep the component definition clean by resolving the commented `sx`,
`onSort`, `order`, `orderBy`, and `onClickRow` wiring around the table usage.
- Around line 81-93: The TideDashboardV2 table defines several non-functional
placeholder columns with empty field values and no renderers, so they will
always display blank cells. Update the columns in TideDashboardV2 to either wire
each one to real data/render logic using the relevant table row fields or
explicitly mark them as intentional scaffolding with a clear TODO/comment so
they are not mistaken for finished UI, including the trailing More column.
In `@app/redux/store/configureStore.dev.js`:
- Around line 112-125: Remove the stray leftover comment in
configureStore.dev.js and extract the duplicated subscribe/throttled persistence
logic into a shared helper so dev and prod stay in sync. Create a small function
such as persistBlipState(store) alongside the existing localStorage helpers, and
have both configureStore.dev.js and configureStore.prod.js call it from their
store.subscribe(throttle(...)) blocks. Keep the helper responsible for reading
selectedClinicId, loggedInUserId, saving selectedClinicId, and persisting
tideDashboardFilters via getTideDashboardFiltersKey.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f591017d-1d32-4b49-81a3-fb44c42913dd
📒 Files selected for processing (32)
__tests__/utils/setupStore.jsapp/bootstrap.jsapp/components/elements/Table.jsapp/pages/clinicworkspace/ClinicPatients.jsapp/pages/clinicworkspace/TideDashboardV2/CGMExclusionQuery.jsapp/pages/clinicworkspace/TideDashboardV2/Cells.jsapp/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.jsapp/pages/clinicworkspace/TideDashboardV2/FilterByCategory.jsapp/pages/clinicworkspace/TideDashboardV2/FilterBySites.jsapp/pages/clinicworkspace/TideDashboardV2/FilterByTags.jsapp/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.jsapp/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.jsapp/pages/clinicworkspace/TideDashboardV2/index.jsapp/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.jsapp/pages/clinicworkspace/TideDashboardV2/tideDashboardFiltersSlice.jsapp/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.jsapp/pages/clinicworkspace/TideDashboardV2/useActiveFiltersCount.jsapp/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.jsapp/pages/clinicworkspace/clinicworkspace.jsapp/pages/clinicworkspace/components/ActiveFilterCount.jsapp/pages/clinicworkspace/components/CategorySegmentedControl.jsapp/pages/clinicworkspace/components/PaginationControls.jsapp/pages/clinicworkspace/components/PatientCount.jsapp/pages/clinicworkspace/components/ResetFilters.jsapp/pages/clinicworkspace/components/SitesFilterDropdown.jsapp/pages/clinicworkspace/components/TagFilterDropdown.jsapp/pages/clinicworkspace/components/TagListCell.jsapp/redux/actions/async.jsapp/redux/reducers/index.jsapp/redux/store/configureStore.dev.jsapp/redux/store/configureStore.prod.jsapp/redux/store/localStorage.js
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
tidepool-org/viz(auto-detected)
💤 Files with no reviewable changes (1)
- app/bootstrap.js
| const trackMetric = () => noop; | ||
| const prefixPopHealthMetric = () => noop; | ||
|
|
||
| import { SPECIAL_FILTER_STATES } from '../ClinicPatients'; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Move SPECIAL_FILTER_STATES out of ClinicPatients.js to avoid a shared-component → page dependency.
SitesFilterDropdown is a shared component (also consumed by TideDashboardV2/FilterBySites.js), but it imports a constant from a page-level module. This inverts the intended dependency direction and risks circular imports as more pages adopt this dropdown.
Consider extracting SPECIAL_FILTER_STATES into a shared constants module (e.g. core/clinicUtils.js) that both ClinicPatients.js and SitesFilterDropdown.js can import from.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js` at line 33, Move
SPECIAL_FILTER_STATES out of ClinicPatients.js and into a shared constants
module so SitesFilterDropdown stays independent of a page-level import. Update
SitesFilterDropdown and ClinicPatients to import the constant from the new
shared location, and make sure any other consumers such as
TideDashboardV2/FilterBySites use the same shared source to avoid circular
dependencies.
| ? t('There are no patients with the current filter(s)') | ||
| : t('There are no results to show'); | ||
|
|
||
| const handleResetFilters = () => dispatch(resetTideDashboardFilters()); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== EmptyContentNode ==\n'
sed -n '1,220p' app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js
printf '\n== TideDashboard filters slice ==\n'
sed -n '1,240p' app/pages/clinicworkspace/TideDashboardV2/tideDashboardFiltersSlice.js
printf '\n== TideDashboard slice ==\n'
sed -n '1,240p' app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js
printf '\n== Search for resetTideDashboardFilters / setOffset / offset handling ==\n'
rg -n "resetTideDashboardFilters|setOffset\\(|offset" app/pages/clinicworkspace/TideDashboardV2 -g '*.js' -g '*.jsx' -g '*.ts' -g '*.tsx'Repository: tidepool-org/blip
Length of output: 5968
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,180p' app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.jsRepository: tidepool-org/blip
Length of output: 176
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== TideDashboardV2.js (1-120) ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js
printf '\n== FilterByTags.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterByTags.js
printf '\n== FilterBySites.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterBySites.js
printf '\n== FilterByCategory.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.jsRepository: tidepool-org/blip
Length of output: 176
Reset pagination when clearing filters.
handleResetFilters only dispatches resetTideDashboardFilters(), so clearing filters from a non-zero page can leave the dashboard on an empty offset even when unfiltered results exist. Reset offset to 0 here as well.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js` at line 33,
Resetting filters currently leaves pagination untouched, so the dashboard can
stay on a non-zero offset after filters are cleared. Update handleResetFilters
to also reset the pagination state by setting offset back to 0 along with
dispatching resetTideDashboardFilters(), using the existing dashboard
state/actions around TideDashboardV2.
| const { data } = useGetTideDashboardPatientsQuery( | ||
| { clinicId: selectedClinicId, offset, category, tags: patientTags, sites: clinicSites, limit: LIMIT }, | ||
| { skip: !selectedClinicId } | ||
| ); | ||
|
|
||
| const activeFiltersCount = useActiveFiltersCount(); | ||
|
|
||
| // reset state on dismount | ||
| useEffect(() => { | ||
| return () => dispatch(resetTideDashboardState()); | ||
| }, []); | ||
|
|
||
| const handleChangeOffset = (newOffset) => dispatch(setOffset(newOffset)); | ||
|
|
||
| if (!data) return null; | ||
|
|
||
| const tableData = data?.data || []; | ||
|
|
||
| const total = data?.meta?.count || 0; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
No loading indicator while patients query resolves.
data starts undefined until the RTK Query resolves, and the component renders nothing (return null) during that window — no skeleton/spinner. This will show a blank page area on every navigation to the tab.
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 51-51: Avoid using the initial state variable in setState
Context: setOffset(newOffset)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.
(setstate-same-var)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 40
- 58, The TideDashboardV2 component returns null while
useGetTideDashboardPatientsQuery is still resolving because it only checks data,
which leaves a blank area on navigation. Update TideDashboardV2.js to use the
query’s loading state (for example from useGetTideDashboardPatientsQuery) and
render an appropriate skeleton/spinner until the request finishes, then fall
through to the existing tableData/total rendering once data is available.
| const dispatch = useDispatch(); | ||
| const selectedClinicId = useSelector(state => state.blip.selectedClinicId); | ||
| const clinic = useSelector(state => state.blip.clinics?.[selectedClinicId]); | ||
| const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Broken selector disables all pruning logic.
state.blip.tideDashboardFilters.patientTags is an array (per tideDashboardFiltersSlice's initialState: { patientTags: [], clinicSites: [] }), so destructuring { patientTags, clinicSites } off it yields undefined for both. Both effects below early-return via !patientTags?.length/!clinicSites?.length, so stale tag/site IDs are never pruned — the entire hook is a no-op.
🐛 Proposed fix
- const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags);
+ const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters);📝 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 { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags); | |
| const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js` at line
10, The selector in usePruneInvalidFilters is reading the wrong shape from
state, so patientTags and clinicSites become undefined and both pruning effects
never run. Update the useSelector call to select the full tideDashboardFilters
slice (or the actual arrays directly) instead of destructuring from
state.blip.tideDashboardFilters.patientTags, then verify the existing
patientTags/clinicSites effects in usePruneInvalidFilters still receive arrays
and can prune stale IDs as intended.
No description provided.