Skip to content

Feature/doctor medicine suggestion#106

Merged
aditya241104 merged 6 commits intomainfrom
feature/doctor-medicine-suggestion
Dec 11, 2025
Merged

Feature/doctor medicine suggestion#106
aditya241104 merged 6 commits intomainfrom
feature/doctor-medicine-suggestion

Conversation

@aditya241104
Copy link
Collaborator

@aditya241104 aditya241104 commented Dec 8, 2025

Project

  • QuickClinic
  • QuickMed

Change Type

  • New Feature/Page/API Endpoint
  • Bug Fix
  • UI Redesign
  • Optimization
  • Other

Stack

  • Frontend
  • Backend
  • Both

Page Type

  • Public
  • Patient
  • Doctor
  • Admin

Route/API Endpoint Status

  • New
  • Existing

What Changed

Route/API Affected

Description

Screenshots (If Applicable)

Mobile View

Desktop View

Code Quality

  • Prettier syntax check passed (npx prettier --check .)

Related Issues

Closes #

Summary by CodeRabbit

  • New Features
    • Added QuickMed integration with direct action links available for medications
    • Introduced real-time medicine suggestions dropdown that displays as doctors type with automatic search
    • Each suggestion item includes an option to quickly view the medication in QuickMed

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
quick-clinic Ready Ready Preview Comment Dec 8, 2025 10:04am
quick-clinic-m9k7 Ready Ready Preview Comment Dec 8, 2025 10:04am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Walkthrough

The 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

Cohort / File(s) Summary
Frontend UI Enhancement
client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx, client/src/pages/doctor/AppointmentDetails.jsx
Added optional QuickMed link per medication row; introduced debounced medicine suggestions with dropdown UI, suggestion fetching on 2+ character input threshold, clickable items to populate fields, and buttons to open QuickMed views in new tabs.
Database Schema Extension
server/models/Appointment/Prescription.js
Added quickmed boolean field with default false to each medication entry in the Prescription schema.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • AppointmentDetails.jsx — Review debounce hook usage, state management for suggestions/showSuggestions, API integration timing, and dropdown UI rendering logic
  • Medications.jsx — Verify conditional QuickMed link rendering based on med.quickmed flag and link target construction
  • Prescription.js — Confirm schema field addition with correct type and default value

Possibly related PRs

Suggested labels

enhancement, UI

Poem

🐰 A flutter of paws, a hop through the code,
Quick suggestions bloom along the med road,
With QuickMed links shining bright as the moon,
Each medicine now has its own little room!
The rabbit approves of this elegant tune.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feature/doctor medicine suggestion' is vague and uses non-descriptive formatting (Feature/X pattern) that doesn't clearly convey the main implementation details or value proposition of the changeset. Revise the title to be more specific and descriptive, e.g., 'Add medicine suggestion dropdown with QuickMed integration in appointment details' to better summarize the main feature.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/doctor-medicine-suggestion

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

📋 PR Auto-Check

📝 Files Changed

client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx
client/src/pages/doctor/AppointmentDetails.jsx
server/models/Appointment/Prescription.js

✨ Code Quality

Prettier Check: ✅ Passed


Auto-generated on 2025-12-08T10:04:35.855Z

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

📋 PR Auto-Check

📝 Files Changed

client/src/components/Patient/AppointmentDetails/prescription/Medications.jsx
client/src/pages/doctor/AppointmentDetails.jsx
server/models/Appointment/Prescription.js

✨ Code Quality

Prettier Check: ✅ Passed


Auto-generated on 2025-12-08T10:06:17.837Z

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

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 absolute positioning but the parent container at line 669 lacks relative positioning. This causes the dropdown to position incorrectly relative to a different ancestor element.

Add relative class 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.medicineName is unnecessary since the Prescription schema only defines a name field for medications, not medicineName. 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 useDebounce to a custom hook as suggested earlier, include this cleanup in the hook itself.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f16c5a9 and 40d6f2c.

📒 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 quickmed boolean field is added correctly with an appropriate default value of false, ensuring backward compatibility with existing prescription documents.

Comment on lines +33 to +34
const [medicineSuggestions, setMedicineSuggestions] = useState([]);
const [showSuggestions, setShowSuggestions] = useState(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +50 to +62
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]
);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +680 to +709
<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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

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.

@aditya241104 aditya241104 merged commit e6d9f8d into main Dec 11, 2025
7 checks passed
@aditya241104 aditya241104 deleted the feature/doctor-medicine-suggestion branch December 11, 2025 04:27
@aditya241104 aditya241104 restored the feature/doctor-medicine-suggestion branch December 11, 2025 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments