Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThe changes introduce a QuickMed integration feature that adds debounced medicine name suggestions with a dropdown UI, renders per-medication QuickMed links in the appointment details view, and extends the Prescription schema to track a quickmed flag per medication entry. Changes
Sequence DiagramsequenceDiagram
participant User
participant AppointmentDetails as AppointmentDetails<br/>(Client)
participant useDebounce as useDebounce<br/>(Hook)
participant API as getMedicineSuggestions<br/>(API)
participant SuggestionUI as Suggestions<br/>Dropdown (UI)
User->>AppointmentDetails: Types medicine name (2+ chars)
AppointmentDetails->>useDebounce: handleMedicineNameChange triggered
activate useDebounce
Note over useDebounce: Debounce timer starts
deactivate useDebounce
User->>AppointmentDetails: Continues typing
activate useDebounce
Note over useDebounce: Timer resets
deactivate useDebounce
User->>AppointmentDetails: Stops typing (debounce threshold met)
activate useDebounce
useDebounce->>API: Fetch suggestions for medicine name
activate API
API-->>useDebounce: Return suggestion results
deactivate API
deactivate useDebounce
AppointmentDetails->>AppointmentDetails: Set medicineSuggestions state
AppointmentDetails->>SuggestionUI: Render dropdown with results
activate SuggestionUI
SuggestionUI-->>User: Display suggestion items + QuickMed buttons
deactivate SuggestionUI
alt User Clicks Suggestion Item
User->>AppointmentDetails: Select suggestion
AppointmentDetails->>AppointmentDetails: Populate medicine field, hide dropdown
else User Clicks QuickMed Button
User->>SuggestionUI: Click QuickMed view button
SuggestionUI->>User: Open /quick-med/medicine/{medicineName} in new tab
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 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 |
📋 PR Auto-Check📝 Files Changed✨ Code QualityPrettier Check: ✅ Passed Auto-generated on 2025-12-08T10:04:35.855Z |
📋 PR Auto-Check📝 Files Changed✨ Code QualityPrettier Check: ✅ Passed Auto-generated on 2025-12-08T10:06:17.837Z |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx (1)
10-16: Missing table header for the new QuickMed column.The table body now has 6 columns (including the new QuickMed link column at lines 34-45), but the header only has 5 columns. This causes a structural mismatch that breaks table semantics and accessibility.
Add a header for the QuickMed column:
<tr className="bg-gray-50"> <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">Med</th> <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">Dose</th> <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">Freq</th> <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">Days</th> <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">Notes</th> + <th className="text-left p-1.5 sm:p-3 font-medium text-[10px] sm:text-sm">QuickMed</th> </tr>client/src/pages/doctor/AppointmentDetails.jsx (1)
669-712: Dropdown missing relative positioning context.The suggestions dropdown (line 678) uses
absolutepositioning but the parent container at line 669 lacksrelativepositioning. This causes the dropdown to position incorrectly relative to a different ancestor element.Add
relativeclass to the parent container:-<div> +<div className="relative"> <input type="text" placeholder="Medicine name"
🧹 Nitpick comments (2)
client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx (1)
34-45: Simplify the medicine name reference.The fallback
med.name || med.medicineNameis unnecessary since the Prescription schema only defines anamefield for medications, notmedicineName. This could cause confusion for future maintainers.<a - href={`/quick-med/medicine/${encodeURIComponent(med.name || med.medicineName)}`} + href={`/quick-med/medicine/${encodeURIComponent(med.name)}`} target="_blank" rel="noopener noreferrer" className="quickmed-button" >client/src/pages/doctor/AppointmentDetails.jsx (1)
68-81: Consider adding cleanup for the debounce timeout.If the component unmounts while a debounced fetch is pending, it may attempt to update state on an unmounted component, causing a React warning. Consider clearing the timeout on unmount.
Add a cleanup effect:
useEffect(() => { return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []);Note: If you extract
useDebounceto a custom hook as suggested earlier, include this cleanup in the hook itself.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx(1 hunks)client/src/pages/doctor/AppointmentDetails.jsx(4 hunks)server/models/Appointment/Prescription.js(1 hunks)
🔇 Additional comments (1)
server/models/Appointment/Prescription.js (1)
28-28: LGTM!The
quickmedboolean field is added correctly with an appropriate default value offalse, ensuring backward compatibility with existing prescription documents.
| const [medicineSuggestions, setMedicineSuggestions] = useState([]); | ||
| const [showSuggestions, setShowSuggestions] = useState(false); |
There was a problem hiding this comment.
Suggestions dropdown displays under all medication inputs simultaneously.
The shared showSuggestions state doesn't track which medication input is active. When typing in one input, the dropdown will appear under every medication entry in the form. Track the active input index to isolate the dropdown.
Add state to track the active medication index:
const [medicineSuggestions, setMedicineSuggestions] = useState([]);
const [showSuggestions, setShowSuggestions] = useState(false);
+const [activeMedicationIndex, setActiveMedicationIndex] = useState(null);Then update handleMedicineNameChange to set the active index and conditionally render the dropdown only when index === activeMedicationIndex.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In client/src/pages/doctor/AppointmentDetails.jsx around lines 33-34 the shared
boolean showSuggestions causes the suggestions dropdown to appear under every
medication input; add a new state like activeMedicationIndex (initialized to
null) to track which medication entry is currently active, update
handleMedicineNameChange to setActiveMedicationIndex(index) when typing and to
setShowSuggestions(true), and change the dropdown render to only show when
showSuggestions && index === activeMedicationIndex; also clear
activeMedicationIndex (set to null) and hide suggestions on blur/selection to
prevent stale dropdowns.
| const useDebounce = (callback, delay) => { | ||
| const timeoutRef = useRef(null); | ||
|
|
||
| return useCallback( | ||
| (...args) => { | ||
| if (timeoutRef.current) { | ||
| clearTimeout(timeoutRef.current); | ||
| } | ||
| timeoutRef.current = setTimeout(() => callback(...args), delay); | ||
| }, | ||
| [callback, delay] | ||
| ); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Move useDebounce outside the component or extract to a separate module.
Defining a custom hook inside the component body recreates it on every render, defeating memoization benefits. Additionally, callback and delay in the dependency array can cause stale closure issues since they reference the outer component's scope.
Extract to a separate utility file (e.g., hooks/useDebounce.js):
import { useRef, useCallback } from 'react';
export const useDebounce = (callback, delay) => {
const timeoutRef = useRef(null);
const debouncedFn = useCallback(
(...args) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => callback(...args), delay);
},
[callback, delay]
);
return debouncedFn;
};Then import and use it in the component. Also consider using useCallback to stabilize the callback reference passed to useDebounce.
🤖 Prompt for AI Agents
In client/src/pages/doctor/AppointmentDetails.jsx around lines 50 to 62, the
custom hook useDebounce is defined inside the component which causes it to be
recreated on every render and can lead to stale closures; move this hook out of
the component into a separate module (e.g., client/src/hooks/useDebounce.js),
export it, and import it into AppointmentDetails.jsx; in the new module import
useRef and useCallback from React and implement the debounced function there,
and in the component ensure you pass a memoized callback (wrap the handler with
useCallback) and a stable delay value so the dependency array doesn’t trigger
unnecessary recreations.
| <button | ||
| key={sugIndex} | ||
| type="button" | ||
| onClick={() => { | ||
| updateMedication(index, 'name', suggestion); | ||
| updateMedication(index, 'quickmed', true); | ||
| setShowSuggestions(false); | ||
| setMedicineSuggestions([]); | ||
| }} | ||
| className="w-full text-left p-3 hover:bg-gray-50 border-b border-gray-100 last:border-b-0" | ||
| > | ||
| <div className="font-medium">{suggestion}</div> | ||
|
|
||
| <button | ||
| type="button" | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| window.open( | ||
| `/quick-med/medicine/${encodeURIComponent(suggestion)}`, | ||
| '_blank', | ||
| 'noopener,noreferrer' | ||
| ); | ||
| }} | ||
| className="px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 flex items-center space-x-1 whitespace-nowrap" | ||
| title={`View ${suggestion} in QuickMed`} | ||
| > | ||
| <span>See in QuickMed</span> | ||
| </button> | ||
| <div className="text-xs text-gray-500">QuickMed ✓</div> | ||
| </button> |
There was a problem hiding this comment.
Invalid HTML: nested <button> elements.
A <button> (lines 693-707) is nested inside another <button> (lines 680-709). This violates HTML specification and causes unpredictable click behavior across browsers. The outer button's click handler will also fire when clicking the inner button despite stopPropagation().
Restructure to use a <div> as the container and separate clickable areas:
-<button
+<div
key={sugIndex}
- type="button"
- onClick={() => {
- updateMedication(index, 'name', suggestion);
- updateMedication(index, 'quickmed', true);
- setShowSuggestions(false);
- setMedicineSuggestions([]);
- }}
className="w-full text-left p-3 hover:bg-gray-50 border-b border-gray-100 last:border-b-0"
>
- <div className="font-medium">{suggestion}</div>
+ <button
+ type="button"
+ onClick={() => {
+ updateMedication(index, 'name', suggestion);
+ updateMedication(index, 'quickmed', true);
+ setShowSuggestions(false);
+ setMedicineSuggestions([]);
+ }}
+ className="font-medium text-left w-full"
+ >
+ {suggestion}
+ </button>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
window.open(
`/quick-med/medicine/${encodeURIComponent(suggestion)}`,
'_blank',
'noopener,noreferrer'
);
}}
className="px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 flex items-center space-x-1 whitespace-nowrap"
title={`View ${suggestion} in QuickMed`}
>
<span>See in QuickMed</span>
</button>
<div className="text-xs text-gray-500">QuickMed ✓</div>
-</button>
+</div>🤖 Prompt for AI Agents
In client/src/pages/doctor/AppointmentDetails.jsx around lines 680 to 709 there
is an invalid nested <button> (outer button wraps an inner “See in QuickMed”
button) which causes unpredictable behavior; replace the outer <button> with a
non-button container (e.g., a <div> with the same classes) and keep the inner
element as a real <button>, or alternatively make the outer element a
role="button" <div> and forward keyboard handlers (onKeyDown for Enter/Space)
and tabIndex=0 to preserve accessibility; ensure the outer container still calls
updateMedication and closes suggestions on click while the inner real button
only opens the QuickMed link and stops propagation.
Project
Change Type
Stack
Page Type
Route/API Endpoint Status
What Changed
Route/API Affected
Description
Screenshots (If Applicable)
Mobile View
Desktop View
Code Quality
npx prettier --check .)Related Issues
Closes #
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.