Skip to content
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

Migrated Scribe to a CARE App + Context #8469

Open
wants to merge 37 commits into
base: develop
Choose a base branch
from
Open

Conversation

shivankacker
Copy link
Member

@shivankacker shivankacker commented Sep 3, 2024

Proposed Changes

Moves Scribe to https://github.com/ohcnetwork/care_scribe_fe

Screen.Recording.2024-11-06.at.12.34.23.PM.mov

Requires care_scribe backend plugin pointing to ohcnetwork/care_scribe#12

Make sure to add the SCRIBE_ENABLED flag through Django Admin to your user

Requires the care_scribe_fe frontend appp. Add that by updating your env to include
REACT_ENABLED_APPS="ohcnetwork/care_livekit_fe,ohcnetwork/care_scribe_fe"

NOTE: Cannot update non arbitrary fields like symptoms, diagnoses for now.

@ohcnetwork/care-fe-code-reviewers

Merge Checklist

  • Add specs that demonstrate bug / test a new feature.
  • Update product documentation.
  • Ensure that UI text is kept in I18n files.
  • Prep screenshot or demo video for changelog entry, and attach it to issue.
  • Request for Peer Reviews
  • Completion of QA

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a dedicated component for rendering keyboard shortcuts.
    • Added a custom hook to observe changes to DOM element attributes.
    • Implemented a voice recording management hook with enhanced functionality.
    • Enhanced date input component to respond to external value changes.
    • Improved autocomplete components for better value management and accessibility.
    • Added file upload functionality for patient management, including audio and document uploads.
    • Added new localization keys to enhance user interface clarity.
  • Bug Fixes

    • Fixed handling of unselect radio input value representation.
    • Adjusted validation logic for temperature input handling.
  • Chores

    • Cleaned up unused API routes related to the Scribe functionalities.

@shivankacker shivankacker requested a review from a team as a code owner September 3, 2024 11:17
Copy link

netlify bot commented Sep 3, 2024

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/672bcc65dff07e3bed14af2a
😎 Deploy Preview https://deploy-preview-8469--care-ohc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@shivankacker shivankacker added waiting for related PR a co-related detail PR is under construction and removed work-in-progress labels Sep 3, 2024
Copy link

github-actions bot commented Sep 3, 2024

👋 Hi, @shivankacker,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Sep 3, 2024
@shivankacker shivankacker added waiting for more data and removed waiting for related PR a co-related detail PR is under construction labels Sep 3, 2024
@github-actions github-actions bot added the stale label Sep 11, 2024
@github-actions github-actions bot removed the merge conflict pull requests with merge conflict label Sep 15, 2024
Copy link

cypress bot commented Sep 15, 2024

CARE    Run #3834

Run Properties:  status check passed Passed #3834  •  git commit 2771ec63fc: Migrated Scribe to a CARE App + Context
Project CARE
Branch Review scribe-context
Run status status check passed Passed #3834
Run duration 04m 35s
Commit git commit 2771ec63fc: Migrated Scribe to a CARE App + Context
Committer Shivank Kacker
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 125
View all changes introduced in this branch ↗︎

@github-actions github-actions bot added merge conflict pull requests with merge conflict and removed stale labels Sep 16, 2024
Copy link

👋 Hi, @shivankacker,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@github-actions github-actions bot added the stale label Sep 25, 2024
@bodhish
Copy link
Member

bodhish commented Oct 7, 2024

@shivankacker please close pending PR's before opening others.

@github-actions github-actions bot removed the stale label Oct 8, 2024
@shivankacker
Copy link
Member Author

@bodhish working on this currently

Copy link

@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

🧹 Outside diff range and nitpick comments (4)
cypress/pageobject/Patient/PatientLogupdate.ts (1)

54-54: Consider adding value validation.

Since this is now a direct integer input field, consider adding validation to ensure the input is within an acceptable range for pulse values.

Example implementation:

  typePulse(pulse: string) {
+   const pulseNum = Number(pulse);
+   if (isNaN(pulseNum) || pulseNum < 0 || pulseNum > 300) {
+     throw new Error('Invalid pulse value. Must be between 0 and 300.');
+   }
    cy.get("#pulse").click().type(pulse);
+   // Verify the value was entered correctly
+   cy.get("#pulse").should('have.value', pulse);
  }
src/components/Form/FormFields/Autocomplete.tsx (2)

159-167: Consider adding props.value to effect dependencies.

While the value observation setup is good, there's a potential race condition if props.value changes while the effect is running. Consider adding props.value to the effect dependencies to ensure proper synchronization.

  useEffect(() => {
    if (props.value !== domValue && typeof domValue !== "undefined")
      props.onChange(domValue);
-  }, [domValue]);
+  }, [domValue, props.value]);

159-182: Well-implemented value observation pattern.

The integration of useValueInjectionObserver with ARIA attributes creates a robust pattern for form value synchronization. This aligns well with the PR objective of making forms aware of existing data. The implementation:

  • Properly separates concerns between DOM observation and state management
  • Follows accessibility best practices with ARIA attributes
  • Uses modern React patterns effectively

This approach could be considered as a pattern for other form components that need similar value awareness capabilities.

src/components/Patient/DailyRounds.tsx (1)

852-855: Simplify the onChange handler.

The current onChange handler can be simplified since it's just passing through the nursing value.

-onChange={(log) =>
-  handleFormFieldChange({
-    name: "nursing",
-    value: log.nursing,
-  })
-}
+onChange={(log) => handleFormFieldChange({ name: "nursing", value: log.nursing })}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6482ea6 and 6814b09.

📒 Files selected for processing (9)
  • cypress/pageobject/Patient/PatientLogupdate.ts (1 hunks)
  • src/Redux/api.tsx (0 hunks)
  • src/Utils/useVoiceRecorder.ts (1 hunks)
  • src/components/Common/DateInputV2.tsx (4 hunks)
  • src/components/Form/FormFields/Autocomplete.tsx (3 hunks)
  • src/components/Patient/DailyRounds.tsx (10 hunks)
  • src/components/Scribe/Scribe.tsx (0 hunks)
  • src/components/Scribe/formDetails.ts (0 hunks)
  • src/pluginTypes.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • src/Redux/api.tsx
  • src/components/Scribe/Scribe.tsx
  • src/components/Scribe/formDetails.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Common/DateInputV2.tsx
  • src/pluginTypes.ts
🧰 Additional context used
🪛 Biome
src/Utils/useVoiceRecorder.ts

[error] 2-2: Do not shadow the global "Error" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

src/components/Patient/DailyRounds.tsx

[error] 706-731: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (9)
src/Utils/useVoiceRecorder.ts (3)

4-10: LGTM: Clean state management implementation.

The hook's state management is well-organized with clear separation of concerns for audio URL, recording status, MediaRecorder instance, blob data, and waveform visualization.


96-119: LGTM: Well-designed public API.

The public methods provide a clean and intuitive interface for controlling the recording functionality.


122-125: 🛠️ Refactor suggestion

Improve error handling in requestRecorder function.

The requestRecorder function should handle potential errors more gracefully and provide meaningful error messages for different failure scenarios.

Consider this improvement:

 async function requestRecorder() {
-  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-  return new MediaRecorder(stream);
+  try {
+    if (!navigator.mediaDevices?.getUserMedia) {
+      throw new Error("Audio recording is not supported in this browser");
+    }
+    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+    return new MediaRecorder(stream);
+  } catch (error) {
+    if (error instanceof DOMException) {
+      switch (error.name) {
+        case "NotAllowedError":
+          throw new Error("Microphone permission denied");
+        case "NotFoundError":
+          throw new Error("No microphone found");
+        default:
+          throw new Error(`Failed to setup audio recording: ${error.message}`);
+      }
+    }
+    throw error;
+  }
 }

Likely invalid or redundant comment.

cypress/pageobject/Patient/PatientLogupdate.ts (1)

54-54: 🛠️ Refactor suggestion

Verify alignment with form field changes.

The change from typeAndSelectOption to direct input aligns with Issue #8978's goal of replacing range auto-complete fields with integer fields. However, similar methods in this class (e.g., typeRespiratory, typeSpo2) still use typeAndSelectOption.

Let's verify if other vital sign fields have been updated in the application code:

Consider updating similar vital sign methods for consistency:

  typePulse(pulse: string) {
    cy.get("#pulse").click().type(pulse);
  }

  typeRespiratory(respiratory: string) {
-   cy.typeAndSelectOption("#resp", respiratory);
+   cy.get("#resp").click().type(respiratory);
  }

  typeSpo2(spo: string) {
-   cy.typeAndSelectOption("#ventilator_spo2", spo);
+   cy.get("#ventilator_spo2").click().type(spo);
  }
src/components/Form/FormFields/Autocomplete.tsx (2)

9-9: LGTM: Import statements are properly organized.

The new imports for useRef and useValueInjectionObserver are correctly placed and support the enhanced value observation functionality.

Also applies to: 17-17


110-110: LGTM: Ref initialization is properly typed.

The menuRef is correctly initialized with proper typing for the dropdown menu container.

src/components/Patient/DailyRounds.tsx (3)

677-682: LGTM! Well-structured form field improvements.

The replacement of range fields with numeric text fields is well implemented with appropriate:

  • Input validation (min/max ranges)
  • Medical thresholds for visual feedback
  • Consistent labeling with units (bpm, mg/dL, %)

Also applies to: 706-711, 738-743, 763-768


863-866: LGTM! Well-organized UI structure.

Good use of:

  • Semantic class names for styling
  • Proper placement of data-scribe-ignore attributes
🧰 Tools
🪛 Biome

[error] 863-945: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


557-561: Verify Scribe plugin initialization and form integration.

The Scribe plugin integration looks good, but let's verify that the form data attribute is properly recognized by the plugin.

✅ Verification successful

Let me gather more information about the Scribe plugin configuration and usage.


Let me check the plugin engine implementation and how it handles plugin components.


Let me check the plugin types and configuration to complete the verification.


Based on the verification results, I can now provide a final response:

Scribe plugin integration is properly configured and implemented.

The integration is correctly set up with:

  • Proper plugin type definition in pluginTypes.ts with ScribeComponentType
  • Correct form data attribute usage with data-scribe-form
  • Proper plugin component initialization through PluginEngine.tsx
  • Consistent data attributes for form fields with data-scribe-ignore where needed
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if Scribe plugin is properly imported and configured
# Test: Search for Scribe plugin configuration
rg -A 5 "PLUGIN_Component.*Scribe"

Length of output: 471


Script:

#!/bin/bash
# Check for PLUGIN_Component definition and imports
rg -l "PLUGIN_Component"

# Check for other Scribe-related configurations or utilities
rg -i "scribe" --type ts --type tsx

# Look for plugin-related type definitions or configurations
ast-grep --pattern 'type PLUGIN_Component = $_'

Length of output: 333


Script:

#!/bin/bash
# Check PluginEngine.tsx implementation
cat src/PluginEngine.tsx

# Check for data attribute usage in the codebase
rg "data-scribe" --type ts --type tsx --type js --type jsx

# Look for plugin component usage pattern
ast-grep --pattern 'const PLUGIN_Component = $_'

Length of output: 1554


Script:

#!/bin/bash
# Check plugin types definition
cat src/pluginTypes.ts

# Check for any Scribe-specific configurations
rg -g '!*.test.*' -g '!*.spec.*' -i "scribe" 

# Look for form data attributes usage
rg "data-" -g '*.tsx' -g '*.ts' -A 2

Length of output: 106618

src/Utils/useVoiceRecorder.ts Outdated Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Outdated Show resolved Hide resolved
Copy link

@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: 1

🧹 Outside diff range and nitpick comments (5)
src/components/Common/TemperatureFormField.tsx (2)

27-27: Add input validation before conversion.

While the conversion chain ensures proper number formatting, it's recommended to validate the input value before conversion to handle potential invalid inputs gracefully.

-          ? Number(fahrenheitToCelsius(parseFloat(value)).toFixed(1)).toString()
+          ? !isNaN(parseFloat(value))
+              ? Number(fahrenheitToCelsius(parseFloat(value)).toFixed(1)).toString()
+              : ""

Line range hint 1-89: Consider additional safety measures for medical application.

As this component handles critical patient data in a medical context, consider implementing:

  1. Type definitions for medically valid temperature ranges
  2. Audit logging for temperature changes (important for medical records)
  3. Visual indicators for abnormal temperature ranges
  4. Internationalization support for temperature units based on locale

Example type definition:

type TemperatureRange = {
  min: number;
  max: number;
  unit: TemperatureUnit;
};

const MEDICAL_TEMPERATURE_RANGES: Record<TemperatureUnit, TemperatureRange> = {
  celsius: { min: 35, max: 41.1, unit: "celsius" },
  fahrenheit: { min: 95, max: 106, unit: "fahrenheit" }
};
src/components/Patient/DailyRounds.tsx (3)

844-855: Consider memoizing the nursing care onChange handler

The onChange handler for NursingCare is recreated on every render. Consider memoizing it with useCallback to optimize performance.

-onChange={(log) =>
-  handleFormFieldChange({
-    name: "nursing",
-    value: log.nursing,
-  })
-}
+onChange={useCallback((log) =>
+  handleFormFieldChange({
+    name: "nursing",
+    value: log.nursing,
+  }), [handleFormFieldChange])}

863-866: Remove unnecessary data-scribe-ignore attribute

The div with class "flex flex-col gap-10" has a data-scribe-ignore attribute, but it's already within a parent element that has the same attribute. This creates unnecessary attribute duplication.

 <div
   className="flex flex-col gap-10 divide-y-2 divide-dashed divide-secondary-600 border-t-2 border-dashed border-secondary-600 pt-6 md:col-span-2"
-  data-scribe-ignore
 >
🧰 Tools
🪛 Biome

[error] 863-945: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


639-640: Improve boolean field handling

The is_experiencing_dysuria field uses string literals "true"/"false" for a boolean field. Consider using actual boolean values for better type safety.

-options={["true", "false"]}
-optionLabel={(c) => t(c === "true" ? "yes" : "no")}
+options={[true, false]}
+optionLabel={(value) => t(value ? "yes" : "no")}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6814b09 and a02d155.

📒 Files selected for processing (5)
  • src/Locale/en.json (12 hunks)
  • src/components/Common/BloodPressureFormField.tsx (1 hunks)
  • src/components/Common/TemperatureFormField.tsx (2 hunks)
  • src/components/Form/FormFields/TextFormField.tsx (3 hunks)
  • src/components/Patient/DailyRounds.tsx (11 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/Common/BloodPressureFormField.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Locale/en.json
  • src/components/Form/FormFields/TextFormField.tsx
🧰 Additional context used
🪛 Biome
src/components/Patient/DailyRounds.tsx

[error] 706-731: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (2)
src/components/Patient/DailyRounds.tsx (2)

677-682: Improved form field validation with TextFormField

The replacement of range fields with TextFormField components includes proper validation constraints and helpful thresholds for medical measurements. Good improvements for:

  • Pulse (0-200 bpm)
  • Blood sugar (0-700 mg/dL)
  • Respiratory rate (0-150 bpm)
  • SpO2 (0-100%)

Also applies to: 706-711, 738-743, 763-768


557-561: Verify data-scribe-form attribute usage

The form has been marked with data-scribe-form attribute, but there's no documentation about its purpose or requirements. This could affect maintainability.

✅ Verification successful

Based on the search results, I can now generate the final response:

The data-scribe-form attribute is part of the Scribe plugin integration

The attribute is used in conjunction with the <PLUGIN_Component __name="Scribe" /> component, which appears to be a legitimate plugin integration. The attribute serves as a form marker for the Scribe plugin functionality.

  • The attribute is properly scoped to the form element that contains the daily rounds data
  • The implementation follows a plugin-based architecture pattern with clear component boundaries
  • The feature can be toggled via the REACT_ENABLE_SCRIBE environment variable
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of data-scribe-form to understand the pattern
rg -l 'data-scribe-form'

# Search for any documentation about scribe form attributes
rg -l 'data-scribe.*form' '*.md'

Length of output: 143


Script:

#!/bin/bash
# Search for any Scribe-related code or documentation
rg -i "scribe" -A 5 -B 5

# Look for plugin component definitions or documentation
ast-grep --pattern 'const PLUGIN_Component = $_'

Length of output: 147402


Script:

#!/bin/bash
# Search for Scribe-related configuration and documentation
rg -l "REACT_ENABLE_SCRIBE|data-scribe" -g "*.md"

# Look for Scribe plugin component usage and configuration
rg "PLUGIN_Component.*Scribe" -A 5 -B 5

# Search for data-scribe-form attribute documentation or related code
rg "data-scribe-form" -A 5 -B 5 -g "!*.{json,map}"

Length of output: 1809

Copy link

@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: 4

🧹 Outside diff range and nitpick comments (3)
src/Utils/useVoiceRecorder.ts (3)

1-2: Be more specific with the notification import.

Instead of importing all exports from Notifications, import only the specific notification function needed. This improves code maintainability and bundle size optimization.

-import * as Notify from "./Notifications";
+import { Error as NotifyError } from "./Notifications";

15-19: Consider combining effects for better state management.

The first effect's logic could be moved into the second effect where the recording state is managed. This would centralize the recorder lifecycle management and reduce the number of effect dependencies.


69-100: Add TypeScript types for better type safety.

The audio analyzer setup could benefit from explicit TypeScript types and error handling.

+  interface AudioAnalyzerConfig {
+    fftSize: number;
+    minDecibels: number;
+    maxDecibels: number;
+  }

   const setupAudioAnalyser = () => {
     let animationFrameId: number;
+    const config: AudioAnalyzerConfig = {
+      fftSize: 32,
+      minDecibels: -90,
+      maxDecibels: -10
+    };

     try {
       audioContext = new (window.AudioContext ||
         (window as any).webkitAudioContext)();
       analyser = audioContext.createAnalyser();
-      analyser.fftSize = 32;
+      Object.assign(analyser, config);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a02d155 and 8c186e5.

📒 Files selected for processing (2)
  • cypress/pageobject/Patient/PatientLogupdate.ts (1 hunks)
  • src/Utils/useVoiceRecorder.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cypress/pageobject/Patient/PatientLogupdate.ts

src/Utils/useVoiceRecorder.ts Outdated Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Outdated Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Outdated Show resolved Hide resolved
Copy link

@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

🧹 Outside diff range and nitpick comments (5)
src/Utils/useSegmentedRecorder.ts (3)

10-10: LGTM! Consider adding JSDoc documentation.

The new state variable for tracking microphone access is well-placed and appropriately initialized.

Add JSDoc documentation to explain the purpose of this state:

+/** Tracks whether the user has granted microphone access permission */
const [microphoneAccess, setMicrophoneAccess] = useState(false);

Line range hint 28-38: Enhance error handling for better user feedback.

While the microphone access state management is correct, the error handling could be more specific to help users troubleshoot issues, especially on iOS devices (ref: Issue #8227).

Consider this improvement:

         setRecorder(newRecorder);
         setMicrophoneAccess(true);
         if (restart) {
           setIsRecording(true);
         }
       },
-      () => {
+      (error) => {
+        const errorMessage = error.name === 'NotAllowedError' 
+          ? t("audio__permission_denied")
+          : error.name === 'NotFoundError'
+          ? t("audio__no_device_found")
+          : t("audio__permission_message");
         Notify.Error({
-          msg: t("audio__permission_message"),
+          msg: errorMessage,
         });
         setIsRecording(false);
         setMicrophoneAccess(false);
       },

Line range hint 13-14: Consider making audio configuration more flexible.

The bufferInterval and splitSizeLimit are hardcoded. Consider making these configurable through hook parameters to support different use cases and device capabilities.

Example implementation:

interface AudioConfig {
  bufferInterval?: number; // milliseconds
  splitSizeLimit?: number; // bytes
  audioBitsPerSecond?: number;
}

const useSegmentedRecording = (config?: AudioConfig) => {
  const bufferInterval = config?.bufferInterval ?? 1000;
  const splitSizeLimit = config?.splitSizeLimit ?? 20_000_000;
  // ... rest of the implementation
}
src/Utils/useVoiceRecorder.ts (2)

74-104: Add error handling to audio analyzer setup.

The setupAudioAnalyser function should handle potential errors when creating audio context and analyzer nodes.

   const setupAudioAnalyser = () => {
     let animationFrameId: number;
-    audioContext = new (window.AudioContext ||
-      (window as any).webkitAudioContext)();
-    analyser = audioContext.createAnalyser();
+    try {
+      audioContext = new (window.AudioContext ||
+        (window as any).webkitAudioContext)();
+      analyser = audioContext.createAnalyser();
+    } catch (error) {
+      Notify.Error({
+        msg: `Failed to initialize audio analyzer: ${
+          error instanceof Error ? error.message : "Unknown error"
+        }`,
+      });
+      return;
+    }

132-156: Add browser compatibility checks.

While the code handles iOS Safari well, it should also check for MediaRecorder API support.

 async function requestRecorder() {
+  if (!navigator.mediaDevices || !window.MediaRecorder) {
+    throw new Error(
+      "Audio recording is not supported in this browser. Please use a modern browser."
+    );
+  }
+
   const constraints: MediaStreamConstraints = {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8c186e5 and df9a8d5.

📒 Files selected for processing (2)
  • src/Utils/useSegmentedRecorder.ts (5 hunks)
  • src/Utils/useVoiceRecorder.ts (1 hunks)
🔇 Additional comments (3)
src/Utils/useSegmentedRecorder.ts (1)

103-112: ⚠️ Potential issue

Address potential race conditions and improve error handling.

The async conversion is good, but there are a few concerns to address:

  1. Add protection against race conditions:
 const startRecording = async () => {
+  if (isRecording) return;
   try {
+    setIsRecording(true); // Set early to prevent multiple calls
     const newRecorder = await requestRecorder();
     setRecorder(newRecorder);
     setMicrophoneAccess(true);
-    setIsRecording(true);
   } catch (error) {
+    setIsRecording(false);
     setMicrophoneAccess(false);
-    throw new Error("Microphone access denied");
+    throw error; // Preserve the original error for better debugging
   }
 };
  1. Consider adding cleanup on component unmount to prevent memory leaks:
src/Utils/useVoiceRecorder.ts (2)

121-130: LGTM! Well-structured hook return value.

The hook exports a clean interface with all necessary controls and state variables.


133-141: Verify iOS audio recording functionality.

The implementation includes iOS-specific constraints, but we should verify if this fully resolves the iPhone issues reported in #8227.

✅ Verification successful

Based on the search results from useVoiceRecorder.ts, I can now generate the final response:

iOS audio recording implementation appears complete and well-handled

The implementation includes all necessary iOS Safari-specific handling:

  • Proper audio constraints (sampleRate: 44100, channelCount: 1)
  • Fallback MIME type handling (webm → mp4) for Safari compatibility
  • Essential audio quality settings (echoCancellation and noiseSuppression)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining iOS-specific workarounds or issues in the codebase

# Search for iOS-related audio recording issues or workarounds
echo "Searching for iOS-specific audio handling..."
rg -i "ios|safari|iphone" --type ts --type tsx

# Search for MediaRecorder configurations that might affect iOS
echo "Checking MediaRecorder configurations..."
rg "MediaRecorder|getUserMedia|audio.*constraints" --type ts --type tsx

Length of output: 368


Script:

#!/bin/bash
# Let's try with correct file type flags and more focused search patterns

# Search for iOS/Safari related audio handling
echo "Searching for iOS-specific audio handling..."
rg -i "ios|safari|iphone" -t typescript

# Search for MediaRecorder and audio constraints
echo "Checking MediaRecorder and audio constraints..."
rg "MediaRecorder|getUserMedia|audio.*constraints" -t typescript

# Search specifically in useVoiceRecorder.ts
echo "Checking useVoiceRecorder.ts specifically..."
rg -A 5 "constraints|MediaRecorder" src/Utils/useVoiceRecorder.ts

# Look for any related test files
echo "Looking for related test files..."
fd -e test.ts -e spec.ts voice

Length of output: 1654

src/Utils/useSegmentedRecorder.ts Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Show resolved Hide resolved
src/Utils/useVoiceRecorder.ts Show resolved Hide resolved
Copy link

github-actions bot commented Nov 6, 2024

👋 Hi, @shivankacker,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Nov 6, 2024
@shivankacker
Copy link
Member Author

Will merge conflicts once PR is tested and approved

@nihal467
Copy link
Member

nihal467 commented Nov 6, 2024

@shivankacker can you clear the merge conflict, to get it ready for review

@github-actions github-actions bot added Deploy-Failed Deplyment is not showing preview and removed merge conflict pull requests with merge conflict labels Nov 6, 2024
Copy link

@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: 0

🧹 Outside diff range and nitpick comments (30)
cypress/e2e/patient_spec/PatientBedManagement.cy.ts (1)

Line range hint 6-54: Consider enhancing test robustness and coverage.

While the test implementation is solid, consider these improvements:

  1. Add data cleanup in afterEach to ensure test isolation
  2. Add error handling for failed bed assignments
  3. Add test cases for edge scenarios:
    • Attempting to assign an already occupied bed
    • Handling network errors during bed assignment
    • Verifying bed status updates in real-time

Here's a suggested enhancement:

 afterEach(() => {
   cy.saveLocalStorage();
+  // Clean up assigned beds
+  cy.intercept('POST', '**/bed/clear/').as('clearBed');
+  patientPage.visitPatient(switchPatientOne);
+  patientLogupdate.clickSwitchBed();
+  cy.get('#clear-button').click();
+  cy.wait('@clearBed');
+  
+  patientPage.visitPatient(switchPatientTwo);
+  patientLogupdate.clickSwitchBed();
+  cy.get('#clear-button').click();
+  cy.wait('@clearBed');
 });

+it("Should handle bed assignment failures gracefully", () => {
+  // Simulate network error
+  cy.intercept('POST', '**/bed/assign/', {
+    statusCode: 500,
+    body: { detail: 'Internal Server Error' }
+  }).as('failedAssignment');
+
+  patientPage.visitPatient(switchPatientOne);
+  patientLogupdate.clickSwitchBed();
+  patientLogupdate.selectBed(switchBedOne);
+  
+  // Verify error handling
+  cy.wait('@failedAssignment');
+  cy.verifyNotification("Failed to assign bed");
+});
cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts (2)

Line range hint 1-14: Consider moving test data to fixtures.

The test data (patient name, user roles) should be moved to a fixture file for better maintainability and reusability. This would make it easier to update test data and share it across different test files.

Example implementation:

// cypress/fixtures/doctor-connect.json
{
  "patientName": "Dummy Patient 11",
  "users": {
    "doctor": "Dev Doctor",
    "nurse": "Dev Staff",
    "teleIcuDoctor": "Dev Doctor Two"
  }
}

// In test file
let testData: any;

before(() => {
  cy.fixture('doctor-connect').then((data) => {
    testData = data;
  });
  loginPage.loginAsDistrictAdmin();
  cy.saveLocalStorage();
});

Line range hint 29-54: Split the test case into multiple focused scenarios.

The current test case violates the single responsibility principle by testing multiple features (user visibility, copy functionality, icon presence, and sorting) in one test. This makes it harder to debug failures and maintain the test.

Consider splitting into these focused test cases:

it("should display users under correct sections", () => {
  patientPage.visitPatient(testData.patientName);
  doctorconnect.clickDoctorConnectButton();
  cy.verifyContentPresence("#doctor-connect-home-doctor", [testData.users.doctor]);
  cy.verifyContentPresence("#doctor-connect-home-nurse", [testData.users.nurse]);
  cy.verifyContentPresence("#doctor-connect-remote-doctor", [testData.users.teleIcuDoctor]);
});

it("should copy phone number correctly", () => {
  patientPage.visitPatient(testData.patientName);
  doctorconnect.clickDoctorConnectButton();
  doctorconnect.CopyFunctionTrigger();
  doctorconnect.clickCopyPhoneNumber("#doctor-connect-home-doctor", testData.users.doctor);
  doctorconnect.verifyCopiedContent();
});

it("should display communication icons", () => {
  patientPage.visitPatient(testData.patientName);
  doctorconnect.clickDoctorConnectButton();
  doctorconnect.verifyIconVisible("#whatsapp-icon");
  doctorconnect.verifyIconVisible("#phone-icon");
});

it("should filter users by role correctly", () => {
  patientPage.visitPatient(testData.patientName);
  doctorconnect.clickDoctorConnectButton();
  
  doctorconnect.clickUsersSortBy("Doctor");
  cy.verifyContentPresence("#doctor-connect-home-doctor", [testData.users.doctor]);
  
  doctorconnect.clickUsersSortBy("Nurse");
  cy.verifyContentPresence("#doctor-connect-home-nurse", [testData.users.nurse]);
  
  doctorconnect.clickUsersSortBy("TeleICU Doctor");
  cy.verifyContentPresence("#doctor-connect-remote-doctor", [testData.users.teleIcuDoctor]);
});
cypress/e2e/resource_spec/ResourcesHomepage.cy.ts (4)

Line range hint 5-11: Consider moving test data to a separate constants file.

The phone number constant could be moved to a shared test data file to maintain consistency across tests and make updates easier.

- const phone_number = "9999999999";

Create a new file cypress/fixtures/testData.ts:

export const TEST_PHONE_NUMBER = "9999999999";

Line range hint 39-63: Enhance resource request creation test reliability.

The resource request creation test could be flaky due to the search dependency. Consider these improvements:

  1. Add retry ability for the search
  2. Add more specific assertions for the facility search results
  3. Include error scenarios
 it("Create a resource request", () => {
   cy.visit("/facility");
-  cy.get("#search").click().type("dummy facility 40");
+  cy.get("#search")
+    .click()
+    .type("dummy facility 40")
+    .should("have.value", "dummy facility 40");
+
   cy.intercept("GET", "**/api/v1/facility/**").as("loadFacilities");
-  cy.get("#facility-details").click();
+  cy.get("#facility-details")
+    .should("be.visible")
+    .and("contain.text", "dummy facility 40")
+    .click();
+
   cy.wait("@loadFacilities").its("response.statusCode").should("eq", 200);
+  
+  // Verify facility details are loaded
+  cy.get("body").should("not.contain.text", "Loading...");

Line range hint 1-89: Consider adding more comprehensive test coverage.

The test suite could benefit from additional scenarios:

  1. Error handling cases (e.g., network errors, validation errors)
  2. Accessibility checks for the resource page
  3. Verification of UI elements and their states

Example additions:

it("Should handle network errors gracefully", () => {
  cy.intercept("GET", "**/api/v1/facility/**", {
    statusCode: 500,
    body: { message: "Internal Server Error" }
  }).as("failedRequest");
  
  // Test error handling
});

it("Should meet accessibility standards", () => {
  cy.visit("/resource");
  cy.injectAxe();
  cy.checkA11y();
});

Line range hint 65-77: Verify resource status updates more thoroughly.

The status update test should verify:

  1. Available status options
  2. Status change reflection in UI
  3. API payload correctness
 it("Update the status of resource", () => {
   cy.visit(createdResource);
+  // Verify available status options
+  const expectedStatuses = ["APPROVED", "REJECTED", "PENDING"];
   resourcePage.clickUpdateStatus();
+  cy.get("[data-testid='status-options']")
+    .should("be.visible")
+    .find("option")
+    .should("have.length", expectedStatuses.length)
+    .each(($el, index) => {
+      expect($el.text()).to.equal(expectedStatuses[index]);
+    });
+
+  // Intercept status update request
+  cy.intercept("PATCH", "**/api/v1/resource/**").as("updateStatus");
   resourcePage.updateStatus("APPROVED");
   resourcePage.clickSubmitButton();
+  
+  // Verify API request
+  cy.wait("@updateStatus").then((interception) => {
+    expect(interception.request.body.status).to.equal("APPROVED");
+  });
+
+  // Verify UI update
+  cy.get("[data-testid='resource-status']")
+    .should("be.visible")
+    .and("contain.text", "APPROVED");
+
   resourcePage.verifySuccessNotification(
     "Resource request updated successfully",
   );
 });
cypress/e2e/facility_spec/FacilityInventory.cy.ts (2)

1-4: Consider implementing a consistent import ordering pattern.

While moving the LoginPage import is harmless, consider organizing imports consistently (e.g., alphabetically) to improve maintainability.

-import FacilityPage from "../../pageobject/Facility/FacilityCreation";
-import FacilityHome from "../../pageobject/Facility/FacilityHome";
-import LoginPage from "../../pageobject/Login/LoginPage";
+import FacilityHome from "../../pageobject/Facility/FacilityHome";
+import FacilityPage from "../../pageobject/Facility/FacilityCreation";
+import LoginPage from "../../pageobject/Login/LoginPage";

Line range hint 28-94: Improve test reliability by following Cypress best practices.

Several improvements could make these tests more robust:

  1. Replace hard-coded cy.wait(3000) with proper Cypress commands:
-cy.wait(3000);
+cy.get('#element').should('be.visible');
  1. Standardize success message verification:
-facilityPage.verifySuccessNotification("Inventory created successfully");
-facilityPage.verifySuccessNotification("Minimum quantiy updated successfully");
+const successMessages = {
+  inventoryCreated: "Inventory created successfully",
+  minimumQuantityUpdated: "Minimum quantiy updated successfully"
+};
+facilityPage.verifySuccessNotification(successMessages.inventoryCreated);
  1. Make element visibility checks more robust:
-if ($body.find("#update-minimum-quantity").is(":visible")) {
+cy.get('body').then(($body) => {
+  const updateBtn = $body.find("#update-minimum-quantity");
+  if (updateBtn.length && updateBtn.is(":visible")) {
src/Utils/useSegmentedRecorder.ts (2)

11-11: Remove redundant comment.

The variable name microphoneAccess is self-explanatory, making the inline comment "New state" unnecessary.

-  const [microphoneAccess, setMicrophoneAccess] = useState(false); // New state
+  const [microphoneAccess, setMicrophoneAccess] = useState(false);

130-130: Remove redundant comment.

The inline comment "Return microphoneAccess" is unnecessary as the code is self-documenting.

-    microphoneAccess, // Return microphoneAccess
+    microphoneAccess,
cypress/e2e/patient_spec/PatientFileUpload.ts (5)

Line range hint 4-28: Consider extracting test constants to a separate file.

The test setup follows good practices with page objects and proper test isolation. However, the test constants (patient names, file names) could be moved to a separate configuration file for better maintainability and reuse across other test files.

+ // testData/patients.ts
+ export const TEST_PATIENTS = {
+   PATIENT_ONE: "Dummy Patient 3",
+   PATIENT_TWO: "Dummy Patient 4",
+   PATIENT_THREE: "Dummy Patient 5"
+ };
+ 
+ export const TEST_FILES = {
+   AUDIO_NAME: "cypress audio",
+   FILE_NAME: "cypress name",
+   MODIFIED_NAME: "cypress modified name"
+ };

Line range hint 30-46: Add verification for audio file format and content.

The audio recording test should verify the format and basic properties of the recorded audio file. Also consider adding error scenarios for when audio recording fails.

 it("Record an Audio and download the file", () => {
   patientPage.visitPatient(patientNameOne);
   visitPatientFileUploadSection.call(patientFileUpload);
   patientFileUpload.recordAudio();
   patientFileUpload.typeAudioName(cypressAudioName);
   patientFileUpload.clickUploadAudioFile();
   cy.verifyNotification("File Uploaded Successfully");
   patientFileUpload.verifyUploadFilePresence(cypressAudioName);
   cy.get("button").contains("Download").click();
   cy.verifyNotification("Downloading file...");
+  // Verify audio file properties
+  cy.get('[data-testid="audio-player"]').should('have.attr', 'src')
+    .and('match', /^blob:http/);
+  // Verify file download
+  cy.readFile('cypress/downloads/' + cypressAudioName)
+    .should('exist');
 });

Line range hint 48-64: Add error scenarios for file upload test.

The file upload test should include scenarios for invalid file types, large files, and network failures. Also verify the archived file's accessibility state.

 it("Upload a File and archive it", () => {
   patientPage.visitPatient(patientNameTwo);
   visitPatientFileUploadSection.call(patientFileUpload);
+  // Test invalid file type
+  patientFileUpload.uploadFile('invalid.exe');
+  cy.verifyNotification("Invalid file type");
+
+  // Test file size limit
+  patientFileUpload.uploadFile('large.pdf');
+  cy.verifyNotification("File size exceeds limit");
+
   patientFileUpload.uploadFile();
   patientFileUpload.typeFileName(cypressFileName);
   patientFileUpload.clickUploadFile();
   cy.verifyNotification("File Uploaded Successfully");
   cy.closeNotification();
   patientFileUpload.verifyUploadFilePresence(cypressFileName);
   patientFileUpload.archiveFile();
   patientFileUpload.clickSaveArchiveFile();
   cy.verifyNotification("File archived successfully");
   patientFileUpload.verifyArchiveFile(cypressFileName);
+  // Verify archived file is not editable
+  patientFileUpload.verifyFileRenameOption(false);
 });

Line range hint 66-115: Enhance user permission test coverage.

The permission test should verify additional operations like file deletion and archival permissions. Also consider testing with more user roles and edge cases.

 it("User-level Based Permission for File Modification", () => {
   loginPage.login("dummynurse1", "Coronasafe@123");
   cy.reload();
   patientPage.visitPatient(patientNameThree);
   visitPatientFileUploadSection.call(patientFileUpload);
   patientFileUpload.uploadFile();
   patientFileUpload.typeFileName(cypressFileName);
   patientFileUpload.clickUploadFile();
   cy.verifyNotification("File Uploaded Successfully");
   cy.closeNotification();
   patientFileUpload.verifyUploadFilePresence(cypressFileName);
+  // Verify additional permissions
+  patientFileUpload.verifyDeleteOption(false);
+  patientFileUpload.verifyArchiveOption(false);
+
   // ... existing permission checks ...
+
+  // Test with additional user roles
+  loginPage.login("doctor1", "Coronasafe@123");
+  cy.reload();
+  patientFileUpload.verifyUploadFilePresence(cypressFileName);
+  patientFileUpload.verifyFileRenameOption(true);
+  patientFileUpload.verifyDeleteOption(true);
+  patientFileUpload.verifyArchiveOption(true);
 });

Line range hint 123-131: Add cross-browser testing configuration.

The tests should be configured to run across different browsers to ensure consistent behavior. Also consider adding parallel test execution for better performance.

+ // cypress.config.ts
+ export default {
+   e2e: {
+     browsers: ['chrome', 'firefox', 'edge'],
+     // Enable parallel execution
+     parallel: true,
+     // Group similar tests
+     testIsolation: false
+   }
+ };
cypress/e2e/assets_spec/AssetsManage.cy.ts (3)

Line range hint 1-120: Consider enhancing test maintainability and reliability.

While reviewing the entire test suite, I noticed some opportunities for improvement:

  1. Test data management:

    • Hard-coded values like "Dummy Facility 40" should be moved to test fixtures
    • Date manipulation could be centralized in a helper
  2. Test isolation:

    • Consider using cy.intercept() to mock network requests
    • Add cleanup in afterEach to ensure consistent state
  3. Error handling:

    • Add timeout configurations for slow operations
    • Include error assertions for negative scenarios

Example implementation for test data management:

// fixtures/asset-data.json
{
  "facility": {
    "name": "Dummy Facility 40"
  },
  "asset": {
    "name": "Dummy Camera",
    "initialLocation": "Camera Location",
    "newLocation": "Dummy Location 1"
  }
}

// support/commands.ts
Cypress.Commands.add('loadAssetTestData', () => {
  cy.fixture('asset-data.json').as('testData');
});

// Example usage in test
beforeEach(() => {
  cy.loadAssetTestData();
  // ... other setup
});

it('Verify Asset Warranty Expiry Label', function() {
  const { asset } = this.testData;
  assetSearchPage.typeSearchKeyword(asset.name);
  // ... rest of the test
});

Line range hint 8-13: Move date utility to a dedicated helper file.

The addDaysToDate function should be moved to a shared helper file for reusability across test files.

// support/helpers/date.ts
export const addDaysToDate = (numberOfDays: number): string => {
  const inputDate = new Date();
  inputDate.setDate(inputDate.getDate() + numberOfDays);
  return inputDate.toISOString().split('T')[0];
};

// Import in test file
import { addDaysToDate } from '../../support/helpers/date';

Line range hint 36-65: Enhance warranty expiry test with data-driven approach.

The warranty expiry test could be more maintainable using a data-driven approach.

const warrantyTestCases = [
  { days: 100, expectedLabel: '' },        // > 3 months
  { days: 80, expectedLabel: '3 months' }, // < 3 months
  { days: 20, expectedLabel: '1 month' },  // < 1 month
  { days: 100, expectedLabel: '' }         // Reset case
];

it('Verify Asset Warranty Expiry Label', () => {
  assetSearchPage.typeSearchKeyword(assetname);
  assetSearchPage.pressEnter();
  assetSearchPage.verifyBadgeContent(assetname);
  assetSearchPage.clickAssetByName(assetname);

  warrantyTestCases.forEach(({ days, expectedLabel }) => {
    assetPage.clickupdatedetailbutton();
    assetPage.scrollintoWarrantyDetails();
    assetPage.enterWarrantyExpiryDate(addDaysToDate(days));
    assetPage.clickassetupdatebutton();
    assetPage.verifyWarrantyExpiryLabel(expectedLabel);
  });
});
cypress/e2e/facility_spec/FacilityHomepage.cy.ts (1)

Line range hint 89-97: Consider enhancing pagination test coverage.

While the basic pagination tests are good, consider adding test cases for:

  • Edge cases (first/last page)
  • Items per page changes
  • Total items count verification
  • Page number validation

Example enhancement:

it("handles pagination edge cases", () => {
  assetPagination.navigateToLastPage();
  assetPagination.verifyNextButtonDisabled();
  assetPagination.navigateToFirstPage();
  assetPagination.verifyPreviousButtonDisabled();
  assetPagination.changeItemsPerPage(50);
  assetPagination.verifyItemsPerPageApplied(50);
});
cypress/e2e/users_spec/UsersCreation.cy.ts (4)

Line range hint 1-200: Consider enhancing test coverage for iPhone-specific scenarios.

Given that Issue #8227 mentions iPhone-specific malfunctions, it would be valuable to add test cases that specifically verify the application's behavior on iPhone viewports.

Consider adding:

it("should work correctly on iPhone viewport", () => {
  cy.viewport('iphone-x');
  // Test user creation flow
  // Test profile updates
  // Verify any audio-related functionality
});

Line range hint 19-31: Consider extracting the makeid utility function.

The makeid function is a utility that could be reused across other test files. Consider moving it to a shared utilities file.

Move this to cypress/pageobject/utils/constants.ts:

export const makeid = (length: number) => {
  let result = "";
  const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
};

Line range hint 32-35: Consider using test data management for user lists.

The hardcoded array of users could be better managed through test data fixtures.

Consider creating a fixture file cypress/fixtures/users.json:

{
  "alreadyLinkedUsers": ["devdoctor", "devstaff2", "devdistrictadmin"]
}

Then import it in the test:

let users;
before(() => {
  cy.fixture('users').then((data) => {
    users = data;
  });
});

Line range hint 36-50: Consider using an enum for error messages.

The error message arrays could be better managed using TypeScript enums or constants in a separate file.

Consider creating cypress/constants/errorMessages.ts:

export enum UserCreationErrors {
  USER_TYPE = "Please select the User Type",
  PHONE_NUMBER = "Please enter valid phone number",
  // ... other messages
}

export enum ProfileErrors {
  REQUIRED = "This field is required",
  PHONE_NUMBER = "Please enter valid phone number"
}
cypress/e2e/patient_spec/PatientRegistration.cy.ts (4)

Line range hint 9-31: Consider improving date handling and age calculation.

The current implementation could be enhanced for better maintainability and robustness:

  1. The hardcoded year value could lead to maintenance issues
  2. Date calculations could benefit from a more robust approach

Consider this improvement:

-const yearOfBirth = "2001";
+const TEST_YEAR_OF_BIRTH = "2001";  // Make the constant name more descriptive
 
 const calculateAge = () => {
-  const currentYear = new Date().getFullYear();
-  return currentYear - parseInt(yearOfBirth);
+  const today = new Date();
+  const birthDate = new Date(`${TEST_YEAR_OF_BIRTH}-01-01`);
+  let age = today.getFullYear() - birthDate.getFullYear();
+  const monthDiff = today.getMonth() - birthDate.getMonth();
+  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
+    age--;
+  }
+  return age;
 };

Line range hint 32-329: Enhance test organization and error coverage.

While the test cases are comprehensive, consider these improvements:

  1. Group test data setup into a separate fixture file
  2. Add negative test cases for form validation
  3. Add assertions for error states in the form fields

Create a new fixture file cypress/fixtures/patient-registration.json:

{
  "validPatient": {
    "name": "Patient With No Consultation",
    "gender": "Male",
    "updatedGender": "Female",
    "address": "Test Patient Address",
    // ... other test data
  },
  "invalidPatient": {
    "name": "",  // for validation testing
    "phone": "invalid",
    // ... invalid test data
  }
}

Then refactor the tests to use this fixture:

describe("Patient Creation with consultation", () => {
  let testData;
  
  before(() => {
    cy.fixture('patient-registration.json').then((data) => {
      testData = data;
    });
    // ... existing setup
  });

  // Add negative test case
  it("should show validation errors for invalid input", () => {
    patientPage.createPatient();
    patientPage.selectFacility(testData.validPatient.facility);
    patientPage.typePatientName(testData.invalidPatient.name);
    patientPage.typePatientPhoneNumber(testData.invalidPatient.phone);
    patientPage.clickCreatePatient();
    
    // Assert validation errors
    cy.get('[data-testid="name-error"]').should('be.visible');
    cy.get('[data-testid="phone-error"]').should('be.visible');
  });

  // ... existing test cases using testData
});

Line range hint 276-329: Enhance transfer test error scenarios.

The transfer test could be expanded to cover more error cases:

  1. Transfer with missing required fields
  2. Transfer with invalid patient data
  3. Network error handling

Add these test cases:

it("should handle transfer errors appropriately", () => {
  // Test missing required fields
  patientPage.createPatient();
  patientPage.selectFacility(patientTransferFacility);
  patientTransfer.clickTransferSubmitButton();
  cy.get('[data-testid="transfer-error"]').should('be.visible');

  // Test network error
  cy.intercept('POST', '/api/transfer', {
    statusCode: 500,
    body: { message: 'Internal Server Error' }
  });
  // ... complete the transfer flow
  cy.get('[data-testid="error-notification"]')
    .should('contain', 'Failed to transfer patient');
});

Line range hint 32-329: Add tests for Scribe integration.

Based on the PR objectives of migrating Scribe to CARE App, consider adding test cases for:

  1. Scribe interaction with existing form data
  2. Audio upload functionality (especially for iPhone)
  3. Integration between Scribe and patient registration

Would you like me to help create test cases for these scenarios? I can provide a detailed implementation that covers:

  • Scribe awareness of pre-filled form data
  • Audio upload validation
  • Cross-browser compatibility tests
public/locale/en.json (2)

254-255: Consider adding more voice-related localization keys for better UX.

The voice-related translations are clear and user-friendly. However, consider adding these additional keys to enhance the user experience:

  • Error states (e.g., "voice_recognition_failed", "network_error_during_recording")
  • Accessibility labels (e.g., "voice_record_button_aria_label")
  • Progress indicators (e.g., "processing_voice_input")

Also applies to: 490-491, 707-707, 1021-1021, 1078-1078, 1095-1096, 1160-1160, 1164-1164, 1191-1192, 1274-1274


334-334: Make the autofilled fields message more descriptive.

The "autofilled_fields" message could be more specific to provide better context to users.

Consider using a more descriptive message like:

-  "autofilled_fields": "Autofilled Fields",
+  "autofilled_fields": "Fields automatically filled from your health records",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between df9a8d5 and 228856c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • cypress/e2e/assets_spec/AssetHomepage.cy.ts (1 hunks)
  • cypress/e2e/assets_spec/AssetsCreation.cy.ts (1 hunks)
  • cypress/e2e/assets_spec/AssetsManage.cy.ts (1 hunks)
  • cypress/e2e/facility_spec/FacilityCreation.cy.ts (1 hunks)
  • cypress/e2e/facility_spec/FacilityHomepage.cy.ts (1 hunks)
  • cypress/e2e/facility_spec/FacilityInventory.cy.ts (1 hunks)
  • cypress/e2e/facility_spec/FacilityManage.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientBedManagement.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientFileUpload.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientLogUpdate.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientPrescription.cy.ts (1 hunks)
  • cypress/e2e/patient_spec/PatientRegistration.cy.ts (1 hunks)
  • cypress/e2e/resource_spec/ResourcesHomepage.cy.ts (1 hunks)
  • cypress/e2e/users_spec/UsersCreation.cy.ts (1 hunks)
  • cypress/e2e/users_spec/UsersManage.cy.ts (1 hunks)
  • public/locale/en.json (12 hunks)
  • src/Routers/AppRouter.tsx (1 hunks)
  • src/Utils/request/api.tsx (0 hunks)
  • src/Utils/useSegmentedRecorder.ts (5 hunks)
  • src/components/Common/BloodPressureFormField.tsx (1 hunks)
  • src/components/Common/DateInputV2.tsx (4 hunks)
  • src/components/Common/TemperatureFormField.tsx (2 hunks)
  • src/components/Common/prescription-builder/PrescriptionDropdown.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • src/Utils/request/api.tsx
✅ Files skipped from review due to trivial changes (7)
  • cypress/e2e/assets_spec/AssetHomepage.cy.ts
  • cypress/e2e/assets_spec/AssetsCreation.cy.ts
  • cypress/e2e/facility_spec/FacilityCreation.cy.ts
  • cypress/e2e/facility_spec/FacilityManage.cy.ts
  • cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts
  • cypress/e2e/patient_spec/PatientLogUpdate.cy.ts
  • cypress/e2e/patient_spec/PatientPrescription.cy.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Routers/AppRouter.tsx
  • src/components/Common/BloodPressureFormField.tsx
  • src/components/Common/DateInputV2.tsx
  • src/components/Common/TemperatureFormField.tsx
  • src/components/Common/prescription-builder/PrescriptionDropdown.tsx
🔇 Additional comments (14)
cypress/e2e/patient_spec/PatientBedManagement.cy.ts (1)

1-4: LGTM! Import changes align with the migration.

The addition of PatientConsultationPage import is consistent with the PR's objective of migrating Scribe functionality.

cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts (2)

Line range hint 16-28: LGTM! Well-structured test setup.

The test lifecycle hooks are properly implemented with good practices:

  • Login state persistence using localStorage
  • Proper cleanup of filters before each test
  • Clear URL verification

Line range hint 56-58: LGTM! Proper test cleanup.

The afterEach hook correctly persists the localStorage state for subsequent tests.

cypress/e2e/resource_spec/ResourcesHomepage.cy.ts (1)

1-3: LGTM! Import organization follows best practices.

The imports are now properly organized at the top of the file, improving code readability.

cypress/e2e/facility_spec/FacilityInventory.cy.ts (1)

Line range hint 5-27: Verify test stability after Scribe migration.

Since this PR involves migrating Scribe to a CARE app, please ensure these inventory management tests remain stable after the migration. Consider:

  1. Running these tests against both old and new environments
  2. Verifying that the page objects and selectors remain valid
  3. Documenting any environment-specific setup required for these tests
src/Utils/useSegmentedRecorder.ts (2)

Line range hint 29-41: Verify microphone access handling on iOS Safari.

Given the reported issues with iPhone (Issue #8227), please ensure this implementation works correctly on iOS Safari. Consider:

  1. iOS Safari requires user interaction before allowing media access
  2. Audio recording might need specific handling for iOS compatibility
#!/bin/bash
# Search for iOS-specific handling in the codebase
rg -i "ios|safari|useragent" --type ts --type tsx

104-113: ⚠️ Potential issue

Enhance error handling in startRecording.

The current implementation has several issues that need attention:

  1. The error message isn't internationalized
  2. The recorder state should be cleaned up on error
  3. The error handling at call sites might need to be documented

Apply these improvements:

 const startRecording = async () => {
   try {
     const newRecorder = await requestRecorder();
     setRecorder(newRecorder);
     setMicrophoneAccess(true);
     setIsRecording(true);
   } catch (error) {
     setMicrophoneAccess(false);
+    setRecorder(null);
+    setIsRecording(false);
-    throw new Error("Microphone access denied");
+    throw new Error(t("audio__permission_denied"));
   }
 };
cypress/e2e/assets_spec/AssetsManage.cy.ts (1)

2-2: LGTM! Import reordering looks good.

The reordering of imports maintains code organization without affecting functionality.

Also applies to: 5-5

cypress/e2e/facility_spec/FacilityHomepage.cy.ts (2)

2-5: LGTM! Import changes are clean and purposeful.

The addition of AssetPagination and reorganization of imports align well with the test file's functionality.


Line range hint 9-168: Test structure follows best practices, but consider adding Scribe-related tests.

The test suite is well-structured using the page object pattern and covers core facility homepage functionality comprehensively. However, given that this PR involves migrating Scribe functionality, consider adding test coverage for:

Let's verify if there are any Scribe-related tests in the codebase:

cypress/e2e/users_spec/UsersManage.cy.ts (2)

4-4: LGTM! Import change aligns with module organization.

The addition of UserPage import from UserSearch module follows good separation of concerns, keeping page object models organized by functionality.


Line range hint 1-168: Verify test coverage for Scribe migration.

The test suite thoroughly covers user management operations but should be verified against the new Scribe CARE app integration.

Let's check for any Scribe-related test coverage:

Consider adding specific test cases to verify:

  1. User permissions interaction with the new Scribe CARE app
  2. Integration points between user management and Scribe functionality
  3. Data consistency when users interact with Scribe features
cypress/e2e/users_spec/UsersCreation.cy.ts (1)

3-3: LGTM! Import statements are properly organized.

The imports are well-structured and the addition of generatePhoneNumber aligns with its usage in the test cases.

Also applies to: 5-5, 8-8

cypress/e2e/patient_spec/PatientRegistration.cy.ts (1)

1-7: LGTM! Well-organized imports.

The new imports for PatientTransfer and generatePhoneNumber are appropriately added and align with their usage in the test cases.

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (7)
src/CAREUI/interactive/KeyboardShortcut.tsx (1)

81-98: Consider improving accessibility and error handling.

While the implementation is solid, consider these enhancements:

  1. Add error handling for invalid shortcut keys
  2. Improve screen reader support
  3. Consider mobile visibility strategy
 export function KeyboardShortcutKey(props: {
   shortcut: string[];
   useShortKeys?: boolean;
 }) {
   const { shortcut, useShortKeys } = props;
+  // Validate shortcut keys
+  const validShortcuts = shortcut.every(key => 
+    key in SHORTCUT_KEY_MAP || key.length > 0
+  );
+  
+  if (!validShortcuts) {
+    console.warn('Invalid shortcut keys provided:', shortcut);
+    return null;
+  }

   return (
-    <div className="hidden shrink-0 items-center md:flex">
+    <div 
+      className="hidden shrink-0 items-center md:flex"
+      role="group"
+      aria-label="Keyboard shortcuts"
+    >
       {shortcut.map((key, idx, keys) => (
         <Fragment key={idx}>
           <kbd 
+            aria-label={`Press ${SHORTCUT_KEY_MAP[key] || key}`}
             className="relative z-10 flex h-6 min-w-6 shrink-0 items-center justify-center rounded-md border border-b-4 border-secondary-400 bg-secondary-100 px-2 text-xs text-black"
           >
src/Utils/useVoiceRecorder.ts (6)

6-10: Consider using a single state object for related states.

The hook uses multiple independent state variables that are conceptually related. Consider combining them into a single state object to make state updates more atomic and prevent potential race conditions.

-  const [audioURL, setAudioURL] = useState("");
-  const [isRecording, setIsRecording] = useState(false);
-  const [recorder, setRecorder] = useState<MediaRecorder | null>(null);
-  const [blob, setBlob] = useState<Blob | null>(null);
-  const [waveform, setWaveform] = useState<number[]>([]); // Decibel waveform
+  const [state, setState] = useState({
+    audioURL: "",
+    isRecording: false,
+    recorder: null as MediaRecorder | null,
+    blob: null as Blob | null,
+    waveform: [] as number[],
+  });

16-20: Add explanatory comment for the recorder reset logic.

The purpose of this effect is not immediately clear. Consider adding a comment explaining why the recorder needs to be reset when recording stops and an audio URL exists.

 useEffect(() => {
+  // Reset recorder after successful recording to free up resources and prepare for next recording
   if (!isRecording && recorder && audioURL) {
     setRecorder(null);
   }
 }, [isRecording, recorder, audioURL]);

28-38: Enhance error handling with specific error types.

The error handling could be more specific to help users understand and resolve issues better. Consider categorizing errors based on their type (permission denied, device not found, etc.).

     } catch (error) {
+      let errorMessage = "Please grant microphone permission to record audio.";
+      if (error instanceof DOMException) {
+        switch (error.name) {
+          case 'NotAllowedError':
+            errorMessage = "Microphone access was denied. Please allow access in your browser settings.";
+            break;
+          case 'NotFoundError':
+            errorMessage = "No microphone found. Please connect a microphone and try again.";
+            break;
+          case 'NotReadableError':
+            errorMessage = "Could not access your microphone. Please check if it's properly connected.";
+            break;
+          default:
+            errorMessage = `Microphone error: ${error.message}`;
+        }
+      }
       Notify.Error({
-        msg: error instanceof Error
-          ? error.message
-          : "Please grant microphone permission to record audio.",
+        msg: errorMessage,
       });

107-120: Add TypeScript return types to control functions.

The control functions lack explicit return type annotations. Adding them would improve type safety and documentation.

-  const startRecording = () => {
+  const startRecording = (): void => {
     setIsRecording(true);
   };

-  const stopRecording = () => {
+  const stopRecording = (): void => {
     setIsRecording(false);
     setWaveform([]);
   };

-  const resetRecording = () => {
+  const resetRecording = (): void => {
     setAudioURL("");
     setBlob(null);
     setWaveform([]);
   };

122-131: Add explicit return type interface.

Define an interface for the hook's return value to improve type safety and documentation.

+interface VoiceRecorderHook {
+  audioURL: string;
+  isRecording: boolean;
+  startRecording: () => void;
+  stopRecording: () => void;
+  blob: Blob | null;
+  waveform: number[];
+  resetRecording: () => void;
+}

-const useVoiceRecorder = (handleMicPermission: (allowed: boolean) => void) => {
+const useVoiceRecorder = (handleMicPermission: (allowed: boolean) => void): VoiceRecorderHook => {

133-157: Add comprehensive JSDoc documentation.

The requestRecorder function would benefit from detailed JSDoc documentation explaining its purpose, parameters, return value, and possible errors.

+/**
+ * Requests access to the user's microphone and creates a MediaRecorder instance.
+ * Includes special handling for iOS Safari compatibility.
+ * 
+ * @throws {Error} When microphone access is denied or initialization fails
+ * @returns {Promise<MediaRecorder>} A configured MediaRecorder instance
+ */
 async function requestRecorder() {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 228856c and 394cd67.

📒 Files selected for processing (2)
  • src/CAREUI/interactive/KeyboardShortcut.tsx (2 hunks)
  • src/Utils/useVoiceRecorder.ts (1 hunks)
🔇 Additional comments (2)
src/CAREUI/interactive/KeyboardShortcut.tsx (2)

1-1: LGTM! Import changes are well-structured.

The import changes follow best practices:

  • Using Fragment from 'react/jsx-runtime' is optimal for performance
  • Relative import path for utils improves maintainability

Also applies to: 4-4


75-78: LGTM! Well-structured component with clear props interface.

The component has a clear single responsibility and good TypeScript typing.

src/Utils/useVoiceRecorder.ts Show resolved Hide resolved
@shivankacker
Copy link
Member Author

@nihal467 resolved merge conflicts, deploy preview failing due to cache issue, nothing else.

@shivankacker shivankacker removed the Deploy-Failed Deplyment is not showing preview label Nov 7, 2024
Copy link

github-actions bot commented Nov 9, 2024

👋 Hi, @shivankacker,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Nov 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge conflict pull requests with merge conflict needs review needs testing
Projects
None yet
4 participants