-
Notifications
You must be signed in to change notification settings - Fork 514
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
Integrates useInfiniteQuery for data fetching and resolves Infinite Load issue in Notes. #9190
Integrates useInfiniteQuery for data fetching and resolves Infinite Load issue in Notes. #9190
Conversation
WalkthroughThe pull request introduces significant refactoring across multiple patient notes and consultation components. The primary focus is on implementing infinite scrolling using React Query's Changes
Assessment against linked issues
Possibly related PRs
Suggested Reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🧰 Additional context used📓 Learnings (1)src/components/Facility/ConsultationDoctorNotes/index.tsx (1)
🔇 Additional comments (7)src/components/Facility/ConsultationDoctorNotes/index.tsx (7)Line range hint The import changes appropriately reflect the migration from manual API calls to React Query hooks.
The useEffect properly handles undefined data with appropriate fallbacks.
The state reset on thread change is properly implemented, ensuring a clean slate for the new thread.
The key combination ensures proper component remounting when patient or thread changes. Line range hint Setting reload to true on every message might cause unnecessary rerenders. Consider using React Query's invalidation instead. useMessageListener((data) => {
const message = data?.message;
if (
(message?.from == "patient/doctor_notes/create" ||
message?.from == "patient/doctor_notes/edit") &&
message?.facility_id == facilityId &&
message?.patient_id == patientId
) {
- setReload(true);
+ queryClient.invalidateQueries({
+ queryKey: ["patient", patientId, thread]
+ });
}
});
Add error handling to mutation. The note submission lacks error handling. Consider adding onError callback to handle API failures gracefully. const { mutate: addNote } = useAddPatientNote({
patientId,
thread,
consultationId,
+ onError: (error) => {
+ Notification.Error({
+ msg: t("error_adding_note"),
+ });
+ },
});
Based on previous discussions, the thread parameter might be needed in the queryKey for proper cache management. - queryKey: ["patient", patientId],
+ queryKey: ["patient", patientId, thread], 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 ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (2)
src/components/Facility/PatientNotesList.tsx (1)
Line range hint
1-105
: Consider implementing a more robust infinite scroll solutionThe current implementation might benefit from using established infinite scroll libraries or implementing virtual scrolling to handle large datasets more efficiently.
Consider these architectural improvements:
- Use a virtual scroll library like
react-window
orreact-virtualized
to efficiently render large lists- Implement scroll position restoration using
ScrollRestoration
fromreact-router-dom
- Add loading states for individual batches to show progress without full-screen loading
- Consider implementing a cursor-based pagination instead of offset-based to prevent issues with concurrent updates
Example implementation structure:
import { FixedSizeList } from 'react-window'; interface NotesListProps { // ... existing props windowHeight: number; } const NotesListRow = ({ index, style, data }) => { const note = data.notes[index]; return ( <div style={style}> <DoctorNote note={note} /> </div> ); }; const PatientNotesList = (props: NotesListProps) => { const [scrollOffset, setScrollOffset] = useState(0); // ... existing state and effects return ( <FixedSizeList height={props.windowHeight} itemCount={state.notes.length} itemSize={120} onScroll={({ scrollOffset }) => { setScrollOffset(scrollOffset); // Trigger load more when near bottom }} > {NotesListRow} </FixedSizeList> ); };src/components/Facility/PatientConsultationNotesList.tsx (1)
Line range hint
41-77
: Enhance infinite scroll implementation to prevent unexpected reloadsThe current implementation might be causing the reported issues with unexpected reloads and lost scroll position. Several improvements are recommended:
- The scroll position issue mentioned in Enhance Discussion Notes Chat History with Infinite Scrolling or Better Navigation Solution #9188 likely occurs because state updates trigger re-renders without preserving scroll position.
- Multiple rapid scroll events could trigger unnecessary fetches.
- The loading state might cause layout shifts during updates.
Consider these improvements:
- Implement scroll position preservation:
const scrollRef = useRef<HTMLDivElement>(null); const scrollPosition = useRef(0); const saveScrollPosition = () => { if (scrollRef.current) { scrollPosition.current = scrollRef.current.scrollTop; } }; const restoreScrollPosition = () => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollPosition.current; } }; // Save position before fetch saveScrollPosition(); fetchNotes().then(() => { setIsLoading(false); setReload?.(false); // Restore position after state update requestAnimationFrame(restoreScrollPosition); });
- Add debouncing to prevent rapid fetches:
const debouncedHandleNext = useMemo( () => debounce(() => { if (state.cPage < state.totalPages) { setState((prevState) => ({ ...prevState, cPage: prevState.cPage + 1, })); setReload?.(true); } }, 250), [state.cPage, state.totalPages] );
- Consider using a virtual scroll library like
react-window
for better performance with large lists.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
src/components/Facility/PatientConsultationNotesList.tsx
(1 hunks)src/components/Facility/PatientNotesList.tsx
(1 hunks)
🔇 Additional comments (2)
src/components/Facility/PatientNotesList.tsx (1)
67-68
: 🛠️ Refactor suggestion
Verify scroll position preservation during thread changes
Setting both loading and reload states simultaneously on thread change might cause scroll position loss, which was mentioned as a key issue in the original bug report.
Let's verify the scroll handling in related components:
Consider debouncing the reload trigger and preserving scroll position:
useEffect(() => {
+ const currentScrollPosition = window.scrollY;
setIsLoading(true);
- setReload(true);
+ // Debounce reload to prevent rapid re-fetches
+ const timeoutId = setTimeout(() => {
+ setReload(true);
+ }, 100);
+ // Restore scroll position after state updates
+ requestAnimationFrame(() => {
+ window.scrollTo(0, currentScrollPosition);
+ });
+ return () => clearTimeout(timeoutId);
}, [thread]);
src/components/Facility/PatientConsultationNotesList.tsx (1)
Line range hint 1-1
: Verify similar scroll handling in related components
Let's check if similar infinite scroll patterns exist in other components that might need the same improvements.
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.
LGTM
LGTM |
…issues/9188/discussion-note-infinite-scroll-bug
…issues/9188/discussion-note-infinite-scroll-bug
@JavidSumra what is the status on this PR |
Hey @nihal467 I'm working on |
…issues/9188/discussion-note-infinite-scroll-bug
…ps://github.com/JavidSumra/care_fe into issues/9188/discussion-note-infinite-scroll-bug
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
♻️ Duplicate comments (1)
src/components/Facility/ConsultationDoctorNotes/index.tsx (1)
63-68
:⚠️ Potential issueAdd error handling to mutation
The mutation lacks error handling for API failures.
Add error handling to the mutation:
const { mutate: addNote } = useAddPatientNote({ patientId, thread, consultationId, + onError: (error) => { + Notification.Error({ + msg: "Failed to add note. Please try again.", + }); + }, });
🧹 Nitpick comments (3)
src/components/Facility/ConsultationDoctorNotes/index.tsx (3)
94-99
: Consider using data destructuring for cleaner state updatesThe effect can be simplified using object destructuring.
- useEffect(() => { - setPatientActive(data?.is_active ?? true); - setPatientName(data?.name ?? ""); - setFacilityName(data?.facility_object?.name ?? ""); - }, [data]); + useEffect(() => { + const { is_active = true, name = "", facility_object } = data ?? {}; + setPatientActive(is_active); + setPatientName(name); + setFacilityName(facility_object?.name ?? ""); + }, [data]);
69-82
: Consider optimistic updates for better UXThe note addition could benefit from optimistic updates to improve user experience.
Consider updating the local state optimistically before the API call completes:
const optimisticNote = { id: 'temp-' + Date.now(), note: noteField, created_date: new Date().toISOString(), created_by: authUser, // ... other required fields }; addNote( { note: noteField, reply_to: reply_to?.id, thread }, { onMutate: async () => { await queryClient.cancelQueries(["/patient", patientId, thread]); const previousNotes = queryClient.getQueryData(["/patient", patientId, thread]); queryClient.setQueryData(["/patient", patientId, thread], old => ({ ...old, notes: [optimisticNote, ...old.notes] })); return { previousNotes }; }, onError: (err, variables, context) => { queryClient.setQueryData(["/patient", patientId, thread], context.previousNotes); } } );
146-153
: Optimize tab click handlerThe tab click handler could be memoized to prevent unnecessary re-renders.
+ const handleTabClick = useCallback((selectedThread: string) => { + if (thread !== selectedThread) { + setThread(selectedThread); + setState(initialData); + setReplyTo(undefined); + setNoteField(""); + } + }, [thread, initialData]); // In JSX: - onClick={() => { - if (thread !== PATIENT_NOTES_THREADS[current]) { - setThread(PATIENT_NOTES_THREADS[current]); - setState(initialData); - setReplyTo(undefined); - setNoteField(""); - } - }} + onClick={() => handleTabClick(PATIENT_NOTES_THREADS[current])}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts
(0 hunks)src/components/Facility/ConsultationDoctorNotes/index.tsx
(5 hunks)
💤 Files with no reviewable changes (1)
- cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts
🧰 Additional context used
📓 Learnings (1)
src/components/Facility/ConsultationDoctorNotes/index.tsx (1)
Learnt from: UdaySagar-Git
PR: ohcnetwork/care_fe#9298
File: src/components/Facility/PatientNotesDetailedView.tsx:147-188
Timestamp: 2024-12-05T22:41:24.173Z
Learning: In the `PatientNotesDetailedView` component, child notes (`state.child_notes`) are fetched along with the parent note in a single query, so a separate loading state for child notes is not required.
🔇 Additional comments (2)
src/components/Facility/ConsultationDoctorNotes/index.tsx (2)
1-1
: Consider adding more specific query keys
The query key structure could be more specific to prevent unintended cache invalidations.
Consider adding the route name to the query key for better cache management:
- queryKey: ["/patient", patientId, thread],
+ queryKey: ["patient", routes.getPatient, patientId, thread],
Also applies to: 17-17, 27-27
160-160
: LGTM: Key prop addition
The key prop addition ensures proper component remounting when thread or patientId changes.
…hub.com:JavidSumra/care_fe into issues/9188/discussion-note-infinite-scroll-bug
LGTM |
@JavidSumra 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
fetchNote
function to resolve unexpected page reloads while scrolling.@ohcnetwork/care-fe-code-reviewers
Merge Checklist
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Refactor