Skip to content

fix: add missing endpoints, fix rollback, and resolve closure bugs#238

Open
Muneerali199 wants to merge 10 commits intoAOSSIE-Org:mainfrom
Muneerali199:fix/high-priority-endpoints-and-fixes
Open

fix: add missing endpoints, fix rollback, and resolve closure bugs#238
Muneerali199 wants to merge 10 commits intoAOSSIE-Org:mainfrom
Muneerali199:fix/high-priority-endpoints-and-fixes

Conversation

@Muneerali199
Copy link
Contributor

@Muneerali199 Muneerali199 commented Mar 15, 2026

Summary

High priority fixes for missing endpoints, broken URLs, and logic bugs

High Priority Fixes

  • Added /agent/refresh endpoint for AgentContext
  • Added /undo_last_action endpoint for undo functionality
  • Created crud.py with all UPDATE/DELETE endpoints:
    • /update_medicine, /delete_medicine
    • /update_blood_pressure, /delete_blood_pressure
    • /update_discharge, /delete_discharge
    • /update_symptoms, /delete_symptoms
    • /update_weight, /delete_weight
  • Backend now returns IDs in create responses for rollback support

URL Fixes

  • ActionExecutor rollback: /appointments/${id} -> /delete_appointment/${id}
  • ActionExecutor rollback delete: POST to /appointments -> /add_appointment

Logic Fixes

  • Fixed useChatEngine stale closure bug using useRef to always get latest conversation
  • Fixed ConversationContext using broken process.env.BASE_URL - now imports from @env

Backend Updates

  • appointments.py: returns {id: lastrowid} on successful create
  • medicine.py: returns {id: lastrowid} on successful create
  • weight.py: returns {id: lastrowid} on successful create

Summary by CodeRabbit

  • New Features

    • Mood and sleep tracking with full CRUD and analytics endpoints
    • Agent endpoints to refresh context and undo recent actions
    • Emergency calling UI and a logout endpoint
  • Improvements

    • Creation endpoints now return new record IDs (appointments, medicine, weight, mood, sleep)
    • Centralized base URL/config handling and stricter model configuration validation
    • Appointment UI/timing and navigation tweaks
    • Some medicine endpoints no longer require per-route auth
  • Bug Fixes

    • Validation now accepts explicit zero values for health metrics
    • Conversation state synchronization and safer week-number rendering in dialogs

Fixed:
- Critical: argparse.parse_args() called twice causing Flask crash
- Critical: Index route returning Response object causing 500 error
- Critical: Hardcoded relative DB paths breaking on wrong CWD
- Critical: ChromaDB relative path crash at import
- Critical: NameError in vector store except block
- Critical: SymptomsScreen null entry crash
- Critical: CalendarScreen broken inline styles
- Critical: Schema missing mood and sleep tables

Security:
- UPDATE profile with no WHERE clause (data corruption)
- Removed broken require_auth decorators (always 401)
- Fixed logout deleting all user data
- Removed mock profile data from schema
- Added .env validation in model.jsx

Missing Endpoints:
- Created mood.py routes (log_mood, get_mood_entries, update_mood, delete_mood)
- Created sleep.py routes (log_sleep, get_sleep_entries, update_sleep, delete_sleep)
- Created analytics.py routes (get_analytics, get_weight_entries, get_mood_entries, get_sleep_entries)

Wrong URLs:
- Fixed ActionExecutor: /create_appointment -> /add_appointment
- Fixed ActionExecutor: /medicine -> /set_medicine
- Fixed RAGService: /get_weight -> /weight
- Fixed RAGService: /get_all_medicine -> /get_medicine

GitHub Issues: AOSSIE-Org#197-236
High Priority Fixes:
- Added /agent/refresh endpoint for AgentContext
- Added /undo_last_action endpoint for undo functionality
- Created crud.py with all UPDATE/DELETE endpoints (medicine, BP, discharge, symptoms, weight)
- Backend now returns IDs in create responses for rollback support

URL Fixes:
- Fixed ActionExecutor rollback: /appointments -> /delete_appointment
- Fixed ActionExecutor rollback: POST to /appointments -> /add_appointment

Logic Fixes:
- Fixed useChatEngine stale closure bug using useRef
- Fixed ConversationContext using process.env.BASE_URL (now imports from @env)

Also updated:
- appointments.py: returns id on create
- medicine.py: returns id on create
- weight.py: returns id on create
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

Adds mood/sleep tracking and analytics blueprints, a generic CRUD blueprint, agent endpoints, centralized BASE_DIR/CHROMADB_PATH with conditional Chroma init, DB path normalization, returns created record IDs, frontend endpoint/env adjustments, and schema additions for mood/sleep tables.

Changes

Cohort / File(s) Summary
Vector store & DB paths
Backend/agent/vector_store.py, Backend/db/db.py
Introduce BASE_DIR and CHROMADB_PATH; add chromadb availability guard (CHROMADB_AVAILABLE), conditional PersistentClient initialization and collections, use CHROMADB_PATH for hashes/storage; normalize DATABASE and SCHEMA_FILE paths via BASE_DIR.
Flask app & agent endpoints
Backend/app.py
Register new blueprints (mood, sleep, analytics, crud), switch env read to FLASK_ENV, and add /agent/refresh and /undo_last_action endpoints with input validation and error handling.
New route blueprints
Backend/routes/mood.py, Backend/routes/sleep.py, Backend/routes/analytics.py, Backend/routes/crud.py
Add full CRUD for mood & sleep, analytics aggregation endpoints, and a generic CRUD surface; each performs DB ops, validation, NotFound handling, commits, and triggers agent cache updates.
Schema changes
Backend/schema.sql
Add mood_logs and sleep_logs tables and remove some profile seed INSERTs.
Create responses include IDs
Backend/routes/appointments.py, Backend/routes/medicine.py, Backend/routes/weight.py
Capture cursor.lastrowid and include created record id in POST responses.
Profile & validation updates
Backend/routes/profile.py, Backend/utils.py
Aggregate missing-field validation in set_profile, add type/format checks and logout route, constrain update_profile with WHERE id, and treat explicitly-provided falsy BP values (0) as present.
Frontend API & env alignment
Frontend/src/services/AnalyticsService.js, Frontend/src/services/RAGService.js, Frontend/src/services/ActionExecutor.js, Frontend/src/services/ConversationContext.js
Align frontend endpoints with backend routes, change logout call to POST /logout, update rollback/create endpoints, and replace inline BASE_URL with imported BASE_URL from @env.
Model & chat hook fixes
Frontend/src/model/model.jsx, Frontend/src/hooks/useChatEngine.js
Add explicit env/config validation for model download logic and guard download; add conversationRef + sync effect to prevent stale conversation state when building model input.
Frontend UI & small fixes
Frontend/src/Screens/* (CalendarScreen.jsx, SymptomsScreen.jsx, EmergencyCallingScreen.jsx, HomeScreen.jsx, ProfileScreen.jsx, SettingsScreen.jsx, SOSAlertScreen.jsx)
UI/styling tweaks, optional-chaining/nullish coalescing fixes, emergency calling flow, navigation replacements for edit actions, adjusted tap-count logic, and minor layout constant extraction.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FlaskApp as App
    participant DB
    participant AgentCache as Agent
    Client->>FlaskApp: POST /log_mood or /log_sleep (create)
    FlaskApp->>DB: INSERT record
    DB-->>FlaskApp: lastrowid
    FlaskApp->>Agent: update cache (data_type, create, id)
    Agent-->>FlaskApp: ack
    FlaskApp-->>Client: 201 { status, message, id }
Loading
sequenceDiagram
    participant Client
    participant FlaskApp as App
    participant VectorStore
    participant ChromaFS as Chroma/FS
    Client->>FlaskApp: POST /agent/refresh or guideline update
    FlaskApp->>VectorStore: ensure CHROMADB_PATH, init client if available
    VectorStore->>ChromaFS: read/write collections, compare/store guideline.hash
    ChromaFS-->>VectorStore: success/error
    VectorStore-->>FlaskApp: result
    FlaskApp-->>Client: 200/500 status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

🐰
I hopped through logs of sleep and mood,
Tuned paths and locks to keep things good,
Blueprints grew and IDs were found,
Caches warmed and hashes bound,
A rabbit cheers — features stitched and sound! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: add missing endpoints, fix rollback, and resolve closure bugs' directly and specifically summarizes the three main changes in the PR: new endpoints, rollback fixes, and closure bug resolution.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

- Fixed RAGService: /get_symptoms -> /symptoms
- Fixed RAGService: /get_blood_pressure -> /blood_pressure
- Fixed AnalyticsService: correct endpoints for weight, symptoms, BP
- Fixed ConversationContext: removed remaining process.env.BASE_URL
- Fixed validate_bp_data: use is not None instead of truthiness
- Fixed profile.py: MissingFieldError now lists only missing fields
- Fixed useChatEngine: import from '../model/model.jsx' explicitly
- Fixed HomeScreen: dueDate check before calculating week numbers
- Fixed HomeScreen: added onPress to floating AI button to navigate to Chat
- ProfileScreen: Edit Information now navigates to BasicDetails
- SettingsScreen: Edit Profile now navigates to BasicDetails
- SettingsScreen: Notification button shows alert (was non-functional)
- SOSAlertScreen: Fixed tap logic - now triggers on 4th tap correctly
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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
Frontend/src/services/ActionExecutor.js (3)

185-210: ⚠️ Potential issue | 🔴 Critical

Post appointment_location to /add_appointment.

The new backend endpoint requires appointment_location, but this payload still sends location. Every create call will fail validation, so the success path and rollback id will never be reached.

Suggested fix
       const appointmentData = {
         title: payload.title,
         description: payload.description || '',
-        location: payload.location || '',
+        appointment_location: payload.location || '',
         appointment_date: this.formatDate(payload.startISO),
         appointment_time: this.formatTime(payload.startISO),
         appointment_status: 'scheduled',
         content: payload.description || '',
         week_number: userContext.current_week || 12
       };
@@
         return {
           success: true,
-          message: `✅ Appointment "${payload.title}" created successfully!\n\n📅 Date: ${appointmentData.appointment_date}\n⏰ Time: ${appointmentData.appointment_time}\n📍 Location: ${appointmentData.location}`,
+          message: `✅ Appointment "${payload.title}" created successfully!\n\n📅 Date: ${appointmentData.appointment_date}\n⏰ Time: ${appointmentData.appointment_time}\n📍 Location: ${appointmentData.appointment_location}`,
           data: result,
           actionType: 'create_appointment',
           appointmentId: result.id || result.appointment_id // Include ID for rollback
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/services/ActionExecutor.js` around lines 185 - 210, The payload
sent to the backend uses the wrong field name: update the appointmentData object
(used in the POST to add_appointment within ActionExecutor.js) to include
appointment_location instead of location (and keep
appointment_date/appointment_time generation via this.formatDate and
this.formatTime unchanged), then ensure the success return still reads
appointmentId from result.id || result.appointment_id so rollback can use the
returned id; verify the fetch to `${BASE_URL}/add_appointment` sends the
corrected appointmentData.

236-256: ⚠️ Potential issue | 🟠 Major

Keep the backend field names and rollback snapshot in the update result.

/update_appointment/<id> reads content, not description, so description edits are dropped today. The success result also omits appointmentId and previousData, which means rollbackUpdateAppointment() can never restore the prior values.

Suggested fix
+      const currentResponse = await fetch(`${BASE_URL}/get_appointment/${payload.id}`);
+      if (!currentResponse.ok) {
+        throw new Error('Failed to load appointment before update');
+      }
+      const previousData = await currentResponse.json();
+
       const updateData = {};
       if (payload.title) updateData.title = payload.title;
-      if (payload.description) updateData.description = payload.description;
+      if (payload.description) updateData.content = payload.description;
       if (payload.location) updateData.appointment_location = payload.location;
       if (payload.startISO) {
         updateData.appointment_date = this.formatDate(payload.startISO);
         updateData.appointment_time = this.formatTime(payload.startISO);
       }
@@
         return {
           success: true,
           message: `✅ Appointment updated successfully!`,
-          actionType: 'update_appointment'
+          actionType: 'update_appointment',
+          appointmentId: payload.id,
+          previousData
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/services/ActionExecutor.js` around lines 236 - 256, The update
flow drops description and omits rollback metadata: ensure payload.description
is mapped to the backend field content (set updateData.content =
payload.description) alongside existing mappings (title, appointment_location,
appointment_date, appointment_time using this.formatDate/formatTime) and capture
a snapshot of the current appointment before the PATCH (e.g., previousData = {
title, content, appointment_location, appointment_date, appointment_time }) so
you can restore on failure; include appointmentId (payload.id) and previousData
in the returned success object so rollbackUpdateAppointment can restore prior
values.

272-291: ⚠️ Potential issue | 🟠 Major

Capture the deleted appointment before calling DELETE.

rollbackDeleteAppointment() only knows how to restore from result.deletedAppointment, but this success path never includes it. Undoing a delete will still always fail.

Suggested fix
+      const existingResponse = await fetch(`${BASE_URL}/get_appointment/${payload.id}`);
+      if (!existingResponse.ok) {
+        throw new Error('Failed to load appointment before delete');
+      }
+      const deletedAppointment = await existingResponse.json();
+
       const response = await fetch(`${BASE_URL}/delete_appointment/${payload.id}`, {
         method: 'DELETE'
       });
 
       if (response.ok) {
         return {
           success: true,
           message: `✅ Appointment deleted successfully!`,
-          actionType: 'delete_appointment'
+          actionType: 'delete_appointment',
+          deletedAppointment
         };
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/services/ActionExecutor.js` around lines 272 - 291, The
deleteAppointment success path doesn't include the deleted appointment object
that rollbackDeleteAppointment expects in result.deletedAppointment; before
calling DELETE in deleteAppointment (or by parsing the DELETE response if the
API returns the removed resource), retrieve and capture the appointment (e.g.,
GET `${BASE_URL}/appointments/${payload.id}`) into a deletedAppointment variable
and include it in the returned success object (e.g., return { success: true,
message: ..., actionType: 'delete_appointment', deletedAppointment }) so
rollbackDeleteAppointment can restore it.
Backend/routes/medicine.py (1)

65-148: ⚠️ Potential issue | 🔴 Critical

These medicine read/update/delete handlers are now public.

require_auth is still defined in this module, but none of the handlers from GET /get_medicine through DELETE /medicine/<id> apply it, and Backend/app.py does not install any app-wide auth middleware. That exposes medication history and allows unauthenticated edits/deletes.

Suggested fix
 `@medicine_bp.route`('/get_medicine', methods=['GET'])
+@require_auth
 `@handle_db_errors`
 def get_all_medicine():
     db = open_db()
     rows = db.execute('SELECT * FROM weekly_medicine').fetchall()
     return jsonify([dict(row) for row in rows]), 200
 
 # Read by week
 `@medicine_bp.route`('/medicine/week/<int:week>', methods=['GET'])
+@require_auth
 `@handle_db_errors`
 def get_week_medicine(week):
     db = open_db()
     rows = db.execute('SELECT * FROM weekly_medicine WHERE week_number = ?', (week,)).fetchall()
     return jsonify([dict(row) for row in rows]), 200
 
 # Read by ID
 `@medicine_bp.route`('/medicine/<int:id>', methods=['GET'])
+@require_auth
 `@handle_db_errors`
 def get_medicine(id):
     db = open_db()
     entry = db.execute('SELECT * FROM weekly_medicine WHERE id = ?', (id,)).fetchone()
     if not entry:
         raise NotFoundError(resource="Medicine entry", resource_id=id)
     return jsonify(dict(entry)), 200
 
 # Update by ID
 `@medicine_bp.route`('/medicine/<int:id>', methods=['PATCH'])
+@require_auth
 `@handle_db_errors`
 def update_medicine(id):
     db = open_db()
     data = request.get_json()
     entry = db.execute('SELECT * FROM weekly_medicine WHERE id = ?', (id,)).fetchone()
@@
 # Delete by ID
 `@medicine_bp.route`('/medicine/<int:id>', methods=['DELETE'])
+@require_auth
 `@handle_db_errors`
 def delete_medicine(id):
     db = open_db()
     entry = db.execute('SELECT * FROM weekly_medicine WHERE id = ?', (id,)).fetchone()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/medicine.py` around lines 65 - 148, These endpoints are
missing authentication: add the require_auth decorator to the five handlers
(get_all_medicine, get_week_medicine, get_medicine, update_medicine,
delete_medicine) so requests must be authenticated before DB access; place
`@require_auth` immediately after the `@medicine_bp.route` decorator (and before
`@handle_db_errors`) for each function; no new imports are needed since
require_auth is already defined in the module.
🧹 Nitpick comments (1)
Frontend/src/model/model.jsx (1)

38-42: Remove unnecessary MODEL_NAME validation.

MODEL_NAME is validated but never used within fetchAvailableGGUFs. Only HF_TO_GGUF is used (line 43). Consider removing the dead validation to avoid confusion.

🔧 Suggested fix
   if (!HF_TO_GGUF) 
       throw new Error("HF_TO_GGUF not configured in environment variables");
-  if (!MODEL_NAME) 
-      throw new Error("MODEL_NAME not configured in environment variables");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/model/model.jsx` around lines 38 - 42, The check that throws
when MODEL_NAME is missing is dead code for the fetchAvailableGGUFs flow; remove
the MODEL_NAME validation (the throw referencing "MODEL_NAME not configured in
environment variables") so only HF_TO_GGUF is validated before
fetchAvailableGGUFs runs. Locate the validation block around HF_TO_GGUF and
MODEL_NAME in the module (the if statements that throw Errors) and delete the
MODEL_NAME check, leaving the HF_TO_GGUF check and any logic inside
fetchAvailableGGUFs unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/app.py`:
- Around line 265-287: The undo endpoint currently expects action_type values
like "add_weight" and a record_id, but callers send high-level types (e.g.,
"weight", "sleep", "appointment") and often omit record_id; update the handler
that reads action_type and record_id to accept those high-level types and map
them to the existing DB table actions (e.g., map "weight" -> DELETE FROM
weekly_weight, "sleep" -> DELETE FROM sleep_logs, "appointment" -> DELETE FROM
appointments, etc.), and when record_id is missing implement logic to delete the
most recent record for the current user from the mapped table (instead of
failing); adjust the code paths that currently branch on action_type (the
if/elif block handling action_type) to use this mapping and optional-record_id
fallback so frontend undo requests succeed.
- Around line 148-151: The handler reads user_id from the request into user_id
but then calls agent.update_cache(data_type="all", operation="refresh") without
using it; update the call to pass the user_id (e.g.,
agent.update_cache(data_type="all", operation="refresh", user_id=user_id) or the
expected parameter name used by update_cache) so the refresh applies to the
correct user context, referencing the user_id variable and the
agent.update_cache(...) call in the handler.

In `@Backend/routes/analytics.py`:
- Around line 55-65: Duplicate route handlers in analytics.py (get_mood_entries
and get_sleep_entries) conflict with existing routes in mood.py and sleep.py;
remove or rename them to avoid routing collisions. Either delete the functions
get_mood_entries and get_sleep_entries from Backend/routes/analytics.py so the
canonical handlers in Backend/routes/mood.py and Backend/routes/sleep.py are
used, or change the analytics endpoints to unique paths (e.g.,
/analytics/get_mood_entries, /analytics/get_sleep_entries) and update any
callers to the new paths; ensure you update or remove any imports/registration
related to these functions to prevent dead code.

In `@Backend/routes/crud.py`:
- Around line 13-42: The new PUT handler update_medicine bypasses the existing
partial-update validators and writes raw request values to SQLite, risking
persisting invalid data and then refreshing the agent cache; fix it by reusing
the existing validation/update logic from the canonical route (e.g., import and
call the validator or update function used in Backend/routes/medicine.py) or
invoke the same validation helpers before executing the DB UPDATE in
update_medicine; ensure you call the same validation functions for fields like
week_number/name/dose/time/note and only apply db.execute with the
validated/normalized values, and keep the agent cache refresh
(get_agent(...).update_cache(...)) after a successful validated update.

In `@Backend/routes/mood.py`:
- Around line 68-71: Handlers currently only accept payload key 'id' (mood_id =
data.get('id')) but the frontend sends date/time-based identifiers; update the
handlers (the mood update and delete handlers that reference mood_id and
data.get('id')) to accept the frontend's identifier key(s) (e.g., 'timestamp' or
'datetime') and/or support both formats. Change the input parsing to check
data.get('id') || data.get('timestamp') (or parse a datetime string), normalize
it to the DB lookup key (convert timestamp to the stored id or query by
datetime), and update the error message to reflect the accepted keys; apply the
same fix to the other handler block around the 97-105 area so both update and
delete use the same identifier contract.

In `@Backend/routes/profile.py`:
- Around line 94-96: The logout route currently only returns a JSON success
message but does not clear the server-side session; update the logout() handler
(profile_bp.route '/logout') to remove authentication state on the server by
clearing relevant session keys (e.g., session.clear() or session.pop('user_id',
None)) and, if using Flask-Login, call logout_user(); then return the same
response and explicitly remove the session cookie on the response so subsequent
requests (and checks like require_auth) no longer treat the user as logged in.

In `@Backend/routes/sleep.py`:
- Around line 22-35: The API uses the field name hours in the sleep create/read
handlers but the frontend expects duration; update the handlers in
Backend/routes/sleep.py to accept and produce duration while preserving
backward-compatibility with hours: read duration from request data if present
(fall back to hours), validate and store the canonical value (e.g., duration) in
the DB insert used by the code block around cursor = db.execute(...), and update
response payloads (the read/list handlers around lines 47-58) to return duration
(and optionally include hours for compatibility) so existing frontend callers
continue to work.
- Around line 69-71: The update/delete handlers currently abort if
data.get('id') is missing (sleep_id) but chat callers send date/time
identifiers; change the handlers (the code that sets sleep_id and the
update_sleep/delete_sleep functions) to accept either an explicit 'id' or a
date/time identifier pair (e.g., 'date' and 'start_time' or a single
'timestamp') — if 'id' is absent, normalize the incoming date/time fields into a
lookup key and query the DB for the matching sleep record to obtain its id
before proceeding; only return the 400 error when neither an 'id' nor valid
date/time fields are provided, and apply the same fix to the other occurrence of
this logic (the block covering lines ~104-113).

In `@Backend/utils.py`:
- Around line 4-11: The validator in validate_bp_data is skipping checks when
values are None, allowing create payloads with null required fields; add a new
boolean parameter require_non_null (default False) to validate_bp_data and, when
True (used by the CREATE endpoint in Backend/routes/blood_pressure.py), treat
keys present with value None as validation failures for required fields
(week_number, systolic, diastolic, time), returning appropriate errors instead
of skipping them; keep the default False so PATCH/partial updates retain the
current behavior and update the CREATE call to pass require_non_null=True.

In `@Frontend/src/hooks/useChatEngine.js`:
- Around line 104-105: The conversation ref is updated in a separate effect,
causing race conditions when sendMessage is called rapidly; instead, update
conversationRef.current inside the setConversation functional updater so the new
array is computed and assigned atomically (e.g., in sendMessage use
setConversation(prev => { const next = [...prev, userMessage];
conversationRef.current = next; return next; }) and mirror this pattern for the
other setConversation call at the second site; also add a re-entry guard in
sendMessage (check or set isGenerating at the start/end) to prevent concurrent
sends.

---

Outside diff comments:
In `@Backend/routes/medicine.py`:
- Around line 65-148: These endpoints are missing authentication: add the
require_auth decorator to the five handlers (get_all_medicine,
get_week_medicine, get_medicine, update_medicine, delete_medicine) so requests
must be authenticated before DB access; place `@require_auth` immediately after
the `@medicine_bp.route` decorator (and before `@handle_db_errors`) for each
function; no new imports are needed since require_auth is already defined in the
module.

In `@Frontend/src/services/ActionExecutor.js`:
- Around line 185-210: The payload sent to the backend uses the wrong field
name: update the appointmentData object (used in the POST to add_appointment
within ActionExecutor.js) to include appointment_location instead of location
(and keep appointment_date/appointment_time generation via this.formatDate and
this.formatTime unchanged), then ensure the success return still reads
appointmentId from result.id || result.appointment_id so rollback can use the
returned id; verify the fetch to `${BASE_URL}/add_appointment` sends the
corrected appointmentData.
- Around line 236-256: The update flow drops description and omits rollback
metadata: ensure payload.description is mapped to the backend field content (set
updateData.content = payload.description) alongside existing mappings (title,
appointment_location, appointment_date, appointment_time using
this.formatDate/formatTime) and capture a snapshot of the current appointment
before the PATCH (e.g., previousData = { title, content, appointment_location,
appointment_date, appointment_time }) so you can restore on failure; include
appointmentId (payload.id) and previousData in the returned success object so
rollbackUpdateAppointment can restore prior values.
- Around line 272-291: The deleteAppointment success path doesn't include the
deleted appointment object that rollbackDeleteAppointment expects in
result.deletedAppointment; before calling DELETE in deleteAppointment (or by
parsing the DELETE response if the API returns the removed resource), retrieve
and capture the appointment (e.g., GET `${BASE_URL}/appointments/${payload.id}`)
into a deletedAppointment variable and include it in the returned success object
(e.g., return { success: true, message: ..., actionType: 'delete_appointment',
deletedAppointment }) so rollbackDeleteAppointment can restore it.

---

Nitpick comments:
In `@Frontend/src/model/model.jsx`:
- Around line 38-42: The check that throws when MODEL_NAME is missing is dead
code for the fetchAvailableGGUFs flow; remove the MODEL_NAME validation (the
throw referencing "MODEL_NAME not configured in environment variables") so only
HF_TO_GGUF is validated before fetchAvailableGGUFs runs. Locate the validation
block around HF_TO_GGUF and MODEL_NAME in the module (the if statements that
throw Errors) and delete the MODEL_NAME check, leaving the HF_TO_GGUF check and
any logic inside fetchAvailableGGUFs unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 920229af-ec0d-4ec7-9828-15f99267a63c

📥 Commits

Reviewing files that changed from the base of the PR and between fda2cfa and 1c60caf.

📒 Files selected for processing (21)
  • Backend/agent/vector_store.py
  • Backend/app.py
  • Backend/db/db.py
  • Backend/routes/analytics.py
  • Backend/routes/appointments.py
  • Backend/routes/crud.py
  • Backend/routes/medicine.py
  • Backend/routes/mood.py
  • Backend/routes/profile.py
  • Backend/routes/sleep.py
  • Backend/routes/weight.py
  • Backend/schema.sql
  • Backend/utils.py
  • Frontend/src/Screens/CalendarScreen.jsx
  • Frontend/src/Screens/SymptomsScreen.jsx
  • Frontend/src/hooks/useChatEngine.js
  • Frontend/src/model/model.jsx
  • Frontend/src/services/ActionExecutor.js
  • Frontend/src/services/AnalyticsService.js
  • Frontend/src/services/ConversationContext.js
  • Frontend/src/services/RAGService.js
💤 Files with no reviewable changes (1)
  • Frontend/src/Screens/CalendarScreen.jsx

Comment on lines +148 to +151
user_id = data.get("user_id", "default")

agent.update_cache(data_type="all", operation="refresh")

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

/agent/refresh ignores the provided user_id.

Line 148 reads user_id, but Line 150 refreshes cache without passing it, so non-default users won’t get their context refreshed.

Suggested fix
-        agent.update_cache(data_type="all", operation="refresh")
+        agent.update_cache(user_id=user_id, data_type="all", operation="update")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/app.py` around lines 148 - 151, The handler reads user_id from the
request into user_id but then calls agent.update_cache(data_type="all",
operation="refresh") without using it; update the call to pass the user_id
(e.g., agent.update_cache(data_type="all", operation="refresh", user_id=user_id)
or the expected parameter name used by update_cache) so the refresh applies to
the correct user context, referencing the user_id variable and the
agent.update_cache(...) call in the handler.

Comment on lines +265 to +287
if not action_type or not record_id:
return jsonify({"error": "action_type and record_id are required"}), 400

db = open_db()

if action_type == "create_appointment":
db.execute("DELETE FROM appointments WHERE id = ?", (record_id,))
elif action_type == "add_weight":
db.execute("DELETE FROM weekly_weight WHERE id = ?", (record_id,))
elif action_type == "log_mood":
db.execute("DELETE FROM mood_logs WHERE id = ?", (record_id,))
elif action_type == "log_sleep":
db.execute("DELETE FROM sleep_logs WHERE id = ?", (record_id,))
elif action_type == "add_medicine":
db.execute("DELETE FROM weekly_medicine WHERE id = ?", (record_id,))
elif action_type == "add_symptom":
db.execute("DELETE FROM weekly_symptoms WHERE id = ?", (record_id,))
elif action_type == "log_bp":
db.execute("DELETE FROM blood_pressure_logs WHERE id = ?", (record_id,))
elif action_type == "log_discharge":
db.execute("DELETE FROM discharge_logs WHERE id = ?", (record_id,))
else:
return jsonify({"error": f"Unknown action type: {action_type}"}), 400
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

Undo endpoint contract is incompatible with current caller payloads.

/undo_last_action requires record_id and action names like add_weight, but Frontend/src/services/RAGService.js sends only high-level types (weight, sleep, appointment, etc.). This will fail most chat undo requests.

Suggested direction
-        if not action_type or not record_id:
-            return jsonify({"error": "action_type and record_id are required"}), 400
+        if not action_type:
+            return jsonify({"error": "action_type is required"}), 400
+
+        action_alias = {
+            "weight": "add_weight",
+            "appointment": "create_appointment",
+            "mood": "log_mood",
+            "sleep": "log_sleep",
+            "medicine": "add_medicine",
+            "symptom": "add_symptom",
+            "blood_pressure": "log_bp",
+            "discharge": "log_discharge",
+        }
+        action_type = action_alias.get(action_type, action_type)
+
+        # If record_id is omitted, resolve last action record id from action history
+        # (or return a clear error that includes required shape expected by callers).

Also applies to: 291-296

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/app.py` around lines 265 - 287, The undo endpoint currently expects
action_type values like "add_weight" and a record_id, but callers send
high-level types (e.g., "weight", "sleep", "appointment") and often omit
record_id; update the handler that reads action_type and record_id to accept
those high-level types and map them to the existing DB table actions (e.g., map
"weight" -> DELETE FROM weekly_weight, "sleep" -> DELETE FROM sleep_logs,
"appointment" -> DELETE FROM appointments, etc.), and when record_id is missing
implement logic to delete the most recent record for the current user from the
mapped table (instead of failing); adjust the code paths that currently branch
on action_type (the if/elif block handling action_type) to use this mapping and
optional-record_id fallback so frontend undo requests succeed.

Comment on lines +55 to +65
@analytics_bp.route('/get_mood_entries', methods=['GET'])
def get_mood_entries():
db = open_db()
week = request.args.get('week')

if week:
rows = db.execute('SELECT * FROM mood_logs WHERE week_number = ? ORDER BY week_number', (week,)).fetchall()
else:
rows = db.execute('SELECT * FROM mood_logs ORDER BY week_number').fetchall()

return jsonify([dict(row) for row in rows]), 200
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

Duplicate route paths conflict with existing mood/sleep blueprints.

/get_mood_entries and /get_sleep_entries are already defined in Backend/routes/mood.py and Backend/routes/sleep.py. Keeping duplicate handlers for identical paths/methods makes routing behavior order-dependent and brittle.

Also applies to: 68-78

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/analytics.py` around lines 55 - 65, Duplicate route handlers
in analytics.py (get_mood_entries and get_sleep_entries) conflict with existing
routes in mood.py and sleep.py; remove or rename them to avoid routing
collisions. Either delete the functions get_mood_entries and get_sleep_entries
from Backend/routes/analytics.py so the canonical handlers in
Backend/routes/mood.py and Backend/routes/sleep.py are used, or change the
analytics endpoints to unique paths (e.g., /analytics/get_mood_entries,
/analytics/get_sleep_entries) and update any callers to the new paths; ensure
you update or remove any imports/registration related to these functions to
prevent dead code.

Comment on lines +13 to +42
@crud_bp.route('/update_medicine', methods=['PUT'])
@handle_db_errors
def update_medicine():
db = open_db()
data = request.get_json()
if not data or 'id' not in data:
return jsonify({"error": "Medicine ID is required"}), 400

entry = db.execute('SELECT * FROM weekly_medicine WHERE id = ?', (data['id'],)).fetchone()
if not entry:
raise NotFoundError(resource="Medicine entry", resource_id=data['id'])

db.execute(
'UPDATE weekly_medicine SET week_number=?, name=?, dose=?, time=?, note=? WHERE id=?',
(
data.get('week_number', entry['week_number']),
data.get('name', entry['name']),
data.get('dose', entry['dose']),
data.get('time', entry['time']),
data.get('note', entry['note']),
data['id']
)
)
db.commit()

db_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "db", "database.db")
agent = get_agent(db_path)
agent.update_cache(data_type="medicine", operation="update")

return jsonify({"status": "success", "message": "Medicine updated"}), 200
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

Don't fork the update paths without the existing validators.

Backend/routes/medicine.py, Backend/routes/blood_pressure.py, Backend/routes/discharge.py, and Backend/routes/weight.py already validate partial updates before committing. These new /update_* handlers write request values straight to SQLite, so they can now persist values the canonical routes would reject and then refresh the cache from invalid data. Please reuse the same validators here or route these calls through the existing update paths.

Also applies to: 66-95, 119-148, 223-250

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/crud.py` around lines 13 - 42, The new PUT handler
update_medicine bypasses the existing partial-update validators and writes raw
request values to SQLite, risking persisting invalid data and then refreshing
the agent cache; fix it by reusing the existing validation/update logic from the
canonical route (e.g., import and call the validator or update function used in
Backend/routes/medicine.py) or invoke the same validation helpers before
executing the DB UPDATE in update_medicine; ensure you call the same validation
functions for fields like week_number/name/dose/time/note and only apply
db.execute with the validated/normalized values, and keep the agent cache
refresh (get_agent(...).update_cache(...)) after a successful validated update.

Comment on lines +68 to +71
mood_id = data.get('id')
if not mood_id:
return jsonify({"error": "Mood ID is required"}), 400

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

Mood update/delete contract is misaligned with current frontend caller.

These handlers are id-only, but existing chat service calls send date/time-based identifiers. This mismatch will block mood edit/delete flows unless both sides are aligned.

Also applies to: 97-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/mood.py` around lines 68 - 71, Handlers currently only accept
payload key 'id' (mood_id = data.get('id')) but the frontend sends
date/time-based identifiers; update the handlers (the mood update and delete
handlers that reference mood_id and data.get('id')) to accept the frontend's
identifier key(s) (e.g., 'timestamp' or 'datetime') and/or support both formats.
Change the input parsing to check data.get('id') || data.get('timestamp') (or
parse a datetime string), normalize it to the DB lookup key (convert timestamp
to the stored id or query by datetime), and update the error message to reflect
the accepted keys; apply the same fix to the other handler block around the
97-105 area so both update and delete use the same identifier contract.

Comment on lines +94 to +96
@profile_bp.route('/logout', methods=['POST'])
def logout():
return jsonify({"status": "success", "message": "Logged out successfully. Local session cleared."}), 200
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

Actually clear the server-side session on logout.

This route only returns a success message right now. If the client still sends an existing session cookie, checks like require_auth will continue to treat the user as logged in.

Suggested fix
-from flask import Blueprint, jsonify, request
+from flask import Blueprint, jsonify, request, session
@@
 `@profile_bp.route`('/logout', methods=['POST'])
 def logout():
+    session.clear()
     return jsonify({"status": "success", "message": "Logged out successfully. Local session cleared."}), 200
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@profile_bp.route('/logout', methods=['POST'])
def logout():
return jsonify({"status": "success", "message": "Logged out successfully. Local session cleared."}), 200
from flask import Blueprint, jsonify, request, session
Suggested change
@profile_bp.route('/logout', methods=['POST'])
def logout():
return jsonify({"status": "success", "message": "Logged out successfully. Local session cleared."}), 200
`@profile_bp.route`('/logout', methods=['POST'])
def logout():
session.clear()
return jsonify({"status": "success", "message": "Logged out successfully. Local session cleared."}), 200
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/profile.py` around lines 94 - 96, The logout route currently
only returns a JSON success message but does not clear the server-side session;
update the logout() handler (profile_bp.route '/logout') to remove
authentication state on the server by clearing relevant session keys (e.g.,
session.clear() or session.pop('user_id', None)) and, if using Flask-Login, call
logout_user(); then return the same response and explicitly remove the session
cookie on the response so subsequent requests (and checks like require_auth) no
longer treat the user as logged in.

Comment on lines +22 to +35
week_number = data.get('week_number')
hours = data.get('hours')
quality = data.get('quality', '')
note = data.get('note', '')

if not week_number or hours is None:
raise MissingFieldError(['week_number', 'hours'])

if quality and quality.lower() not in VALID_QUALITY:
return jsonify({"error": f"Invalid quality. Must be one of: {', '.join(VALID_QUALITY)}"}), 400

cursor = db.execute(
'INSERT INTO sleep_logs (week_number, hours, quality, note) VALUES (?, ?, ?, ?)',
(week_number, hours, quality.lower() if quality else '', note)
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

hours vs duration mismatch breaks current sleep API consumers.

Current create/read payloads use hours, while existing frontend callers use duration. This will cause failed creates and incorrect analytics parsing.

Suggested compatibility fix
-    hours = data.get('hours')
+    hours = data.get('hours', data.get('duration'))
...
-    return jsonify([dict(row) for row in rows]), 200
+    normalized = []
+    for row in rows:
+        item = dict(row)
+        item['duration'] = item.get('hours')
+        normalized.append(item)
+    return jsonify(normalized), 200

Also applies to: 47-58

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/sleep.py` around lines 22 - 35, The API uses the field name
hours in the sleep create/read handlers but the frontend expects duration;
update the handlers in Backend/routes/sleep.py to accept and produce duration
while preserving backward-compatibility with hours: read duration from request
data if present (fall back to hours), validate and store the canonical value
(e.g., duration) in the DB insert used by the code block around cursor =
db.execute(...), and update response payloads (the read/list handlers around
lines 47-58) to return duration (and optionally include hours for compatibility)
so existing frontend callers continue to work.

Comment on lines +69 to +71
sleep_id = data.get('id')
if not sleep_id:
return jsonify({"error": "Sleep ID is required"}), 400
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

Sleep update/delete identifier contract is inconsistent with chat caller payloads.

These endpoints require id, but current chat flows send date/time identifiers. Without alignment, update/delete operations will fail at runtime.

Also applies to: 104-113

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/routes/sleep.py` around lines 69 - 71, The update/delete handlers
currently abort if data.get('id') is missing (sleep_id) but chat callers send
date/time identifiers; change the handlers (the code that sets sleep_id and the
update_sleep/delete_sleep functions) to accept either an explicit 'id' or a
date/time identifier pair (e.g., 'date' and 'start_time' or a single
'timestamp') — if 'id' is absent, normalize the incoming date/time fields into a
lookup key and query the DB for the matching sleep record to obtain its id
before proceeding; only return the 400 error when neither an 'id' nor valid
date/time fields are provided, and apply the same fix to the other occurrence of
this logic (the block covering lines ~104-113).

Comment on lines +4 to 11
if data.get('week_number') is not None and (not isinstance(data['week_number'], int) or data['week_number'] < 1):
errors["week_number"] = "week_number must be a positive integer."

if data.get('systolic') and (not isinstance(data['systolic'], int) or not (50 < data['systolic'] < 300)):
if data.get('systolic') is not None and (not isinstance(data['systolic'], int) or not (50 < data['systolic'] < 300)):
errors["systolic"] = "systolic must be an integer between 50 and 300."

if data.get('diastolic') and (not isinstance(data['diastolic'], int) or not (30 < data['diastolic'] < 200)):
if data.get('diastolic') is not None and (not isinstance(data['diastolic'], int) or not (30 < data['diastolic'] < 200)):
errors["diastolic"] = "diastolic must be an integer between 30 and 200."
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

🧩 Analysis chain

🏁 Script executed:

# First, let's find the Backend directory and understand the structure
find . -type f -name "utils.py" | grep -i backend
find . -type f -name "*blood_pressure*" | grep -i backend

Repository: AOSSIE-Org/BabyNest

Length of output: 116


🏁 Script executed:

# List files to understand the repo structure
git ls-files | head -30

Repository: AOSSIE-Org/BabyNest

Length of output: 892


🏁 Script executed:

# Check the size and read Backend/utils.py
wc -l Backend/utils.py

Repository: AOSSIE-Org/BabyNest

Length of output: 82


🏁 Script executed:

# Check the size and read Backend/routes/blood_pressure.py
wc -l Backend/routes/blood_pressure.py

Repository: AOSSIE-Org/BabyNest

Length of output: 99


🏁 Script executed:

# Read Backend/utils.py completely
cat -n Backend/utils.py

Repository: AOSSIE-Org/BabyNest

Length of output: 2526


🏁 Script executed:

# Read Backend/routes/blood_pressure.py completely
cat -n Backend/routes/blood_pressure.py

Repository: AOSSIE-Org/BabyNest

Length of output: 6317


Null values bypass required-field validation in create flow.

In Backend/routes/blood_pressure.py (line 20), the CREATE endpoint only checks key presence. The validation function in Backend/utils.py (lines 4-11) skips checks when values are None. Combined, payloads like {"week_number": null, "systolic": null, "diastolic": null, "time": "12:30"} pass both checks and reach the database.

The proposed fix is correct: add a require_non_null parameter to validate_bp_data(), use it in the CREATE endpoint to enforce non-null values for required fields, and keep the default False for the PATCH endpoint where partial updates are supported.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/utils.py` around lines 4 - 11, The validator in validate_bp_data is
skipping checks when values are None, allowing create payloads with null
required fields; add a new boolean parameter require_non_null (default False) to
validate_bp_data and, when True (used by the CREATE endpoint in
Backend/routes/blood_pressure.py), treat keys present with value None as
validation failures for required fields (week_number, systolic, diastolic,
time), returning appropriate errors instead of skipping them; keep the default
False so PATCH/partial updates retain the current behavior and update the CREATE
call to pass require_non_null=True.

Comment on lines +104 to +105
// Important: Use ref to get the latest conversation state
const updatedConversationForModel = [...conversationRef.current, userMessage];
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all writes to conversationRef and where updatedConversationForModel is built.
rg -n -C2 'conversationRef\.current\s*=' Frontend/src/hooks/useChatEngine.js
rg -n -C3 'updatedConversationForModel|setConversation\(\s*prev\s*=>\s*\{' Frontend/src/hooks/useChatEngine.js

Repository: AOSSIE-Org/BabyNest

Length of output: 1691


🏁 Script executed:

#!/bin/bash
# Find the sendMessage function and check for isGenerating guard
rg -n -B5 -A50 'const sendMessage|function sendMessage' Frontend/src/hooks/useChatEngine.js | head -100

Repository: AOSSIE-Org/BabyNest

Length of output: 2013


🏁 Script executed:

#!/bin/bash
# Check lines 62-75 for re-entry guard
sed -n '62,75p' Frontend/src/hooks/useChatEngine.js

Repository: AOSSIE-Org/BabyNest

Length of output: 457


Potential history loss on rapid sends (ref updated too late).

At Line 105, updatedConversationForModel is built from conversationRef.current, but the ref is only synced in an effect after the state update. If sendMessage is triggered again before the effect runs, the second call reads stale ref content and constructs model history that skips the previous message.

With no re-entry guard (e.g., if (isGenerating) return), concurrent sends can occur. The sequence is:

  • Call A: schedules state update, reads ref (still old), model receives [old + A]
  • Call B: schedules state before effect A runs, reads ref (still old), model receives [old + B]
  • Effect syncs ref after, but damage is done—model context missing prior turns

Suggest updating conversationRef atomically inside the setConversation functional update, not in a separate effect:

setConversation(prev => {
  const newHistory = [...prev, userMessage];
  conversationRef.current = newHistory;
  saveChats(newHistory);
  return newHistory;
});

Apply the same pattern to other setConversation calls (line 183).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/hooks/useChatEngine.js` around lines 104 - 105, The conversation
ref is updated in a separate effect, causing race conditions when sendMessage is
called rapidly; instead, update conversationRef.current inside the
setConversation functional updater so the new array is computed and assigned
atomically (e.g., in sendMessage use setConversation(prev => { const next =
[...prev, userMessage]; conversationRef.current = next; return next; }) and
mirror this pattern for the other setConversation call at the second site; also
add a re-entry guard in sendMessage (check or set isGenerating at the start/end)
to prevent concurrent sends.

- EmergencyCallingScreen now uses Linking API to make real emergency calls
- Shows confirmation dialog before calling 911
- Added proper UI with call button and emergency contacts placeholder
- Updated styles for better UX

Note: Video demonstration needed to show emergency call functionality working.
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: 6

🧹 Nitpick comments (4)
Frontend/src/Screens/CalendarScreen.jsx (1)

332-333: Good refactor: Extracted magic number to named constant.

The constant extraction improves readability. However, consider moving SCHEDULE_OFFSET_MINUTES and timeSlotHeight outside the component since they are static values, avoiding recreation on each render.

Additionally, the offset value of 370 (6:10 AM in minutes) seems inconsistent with the time grid starting at 8:00 AM (480 minutes). Verify this value produces correct vertical alignment for appointments.

♻️ Suggested refactor: move constants outside component
 const months = [
   'January',
   ...
   'December',
 ];
+
+const timeSlotHeight = 80;
+const SCHEDULE_OFFSET_MINUTES = 370; // Offset to position appointments in time grid
+
 const generateWeekDates = startDate => {

Then remove lines 332-333 from inside the component.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/CalendarScreen.jsx` around lines 332 - 333, Move the two
static values out of the CalendarScreen component to module-level constants so
they are not recreated on each render: lift timeSlotHeight and
SCHEDULE_OFFSET_MINUTES to the top of the file (module scope) and remove their
declarations from inside CalendarScreen; also verify and correct the offset
value—if the time grid starts at 8:00 AM (480 minutes) then
SCHEDULE_OFFSET_MINUTES should reflect that (e.g., 480) or be computed from an
existing scheduleStartMinutes constant to ensure vertical alignment of
appointments.
Frontend/src/Screens/SettingsScreen.jsx (1)

1-1: Stale file path comment.

The comment says src/components/ProfileScreen.js but this file is SettingsScreen.jsx. Consider removing or correcting this comment to avoid confusion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/SettingsScreen.jsx` at line 1, Remove or update the
stale header comment referencing src/components/ProfileScreen.js in
SettingsScreen.jsx; locate the top-of-file comment (the line containing "//
src/components/ProfileScreen.js") and either delete it or replace it with an
accurate comment such as the current file/component name (e.g., "//
src/Screens/SettingsScreen.jsx" or "// SettingsScreen component") so the file
header accurately reflects the file and component.
Frontend/src/Screens/EmergencyCallingScreen.jsx (2)

2-2: Unused import: Image

Image is imported but no longer used in the JSX after the refactor to placeholder contacts. The corresponding contactImage style on line 97 is also unused.

🧹 Suggested cleanup
-import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, Linking, Platform } from "react-native";
+import { View, Text, TouchableOpacity, StyleSheet, Alert, Linking } from "react-native";

And optionally remove the unused style:

-  contactImage: { width: 50, height: 50, borderRadius: 25, marginHorizontal: 10 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` at line 2, Remove the unused
Image import and the unused contactImage style: delete "Image" from the import
list in EmergencyCallingScreen.jsx and remove the contactImage entry from the
StyleSheet (or any references to it) so there are no dead imports or styles left
(look for the imported symbol Image and the StyleSheet key contactImage).

2-2: Unused import: Platform

Platform is imported but not used anywhere in this file.

🧹 Suggested fix
-import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, Linking, Platform } from "react-native";
+import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, Linking } from "react-native";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` at line 2, The import list
in EmergencyCallingScreen.jsx includes an unused symbol Platform; remove
Platform from the import statement (the line importing View, Text,
TouchableOpacity, StyleSheet, Image, Alert, Linking, Platform) so only used
modules remain to eliminate the unused import warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/db/db.py`:
- Line 24: Replace the two separate exists()+stat() checks with a single
race-safe helper (e.g., file_missing_or_empty(path) or
is_database_missing_or_empty(path)) that performs a single os.stat() call inside
a try/except FileNotFoundError and returns True if the file is missing or its
st_size == 0; then call that helper wherever the code currently uses
os.path.exists(DATABASE) or os.stat(DATABASE).st_size checks (reference the
DATABASE variable and replace both occurrences around the startup checks) so the
check is atomic and TOCTOU-safe.
- Line 3: The code currently imports fcntl (in Backend/db/db.py) which breaks on
Windows; either add a cross-platform fallback or document POSIX-only support:
implement a small compatibility layer that tries "import fcntl" and on
ImportError/import failure imports "msvcrt" and exposes the same file-locking
API (e.g., provide lock_file/unlock_file functions or a FileLock class used by
any existing callers) mapping fcntl.flock semantics to msvcrt.locking, or if you
choose POSIX-only, update the README/CI to state and enforce Linux/POSIX support
and raise a clear RuntimeError at import time if fcntl is unavailable. Ensure
the symbols referenced (fcntl, msvcrt, lock_file/unlock_file or FileLock) are
used consistently so callers in this module don't need to change.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx`:
- Line 86: In the callingText style object (callingText), fix the unterminated
string literal for textAlign by replacing the mismatched `"center'` with a
properly quoted string (e.g., "center" or 'center') so the style reads
textAlign: "center" and the file parses correctly.
- Around line 12-30: The handleEmergencyCall function leaves isCalling true when
Linking.openURL succeeds; update the success path so setIsCalling(false) is
called after a successful openURL (e.g., chain a .then(() =>
setIsCalling(false)) or use async/await with try/finally around
Linking.openURL(`tel:${EMERGENCY_NUMBER}`)) so both success and failure reset
isCalling; reference handleEmergencyCall, setIsCalling, Linking.openURL and
EMERGENCY_NUMBER when making the change.

In `@Frontend/src/Screens/SettingsScreen.jsx`:
- Around line 119-123: The IconButton currently ignores the onPress passed from
SettingsScreen, so update the IconButton component to accept an onPress prop and
use a touchable container (e.g., TouchableOpacity or Pressable) instead of a
plain View: add onPress to IconButton's props signature, wrap the rendered
content in TouchableOpacity/Pressable and pass the onPress handler through (also
import TouchableOpacity/Pressable), and preserve existing icon and label
rendering so the Notification button in SettingsScreen will respond to taps.

In `@Frontend/src/Screens/SOSAlertScreen.jsx`:
- Around line 11-15: The tap counting logic uses a stale closure value (tapCount
+ 1) which can miss increments under rapid presses; update the handler to use a
functional state updater with setTapCount(prev => ...) so each increment is
based on the latest state, compute newCount = prev + 1 inside that updater, call
navigation.navigate("EmergencyCalling") when newCount >= 4, and reset the state
to 0 there (otherwise return newCount); update references to
tapCount/setTapCount and keep the EmergencyCalling navigation call inside the
functional updater.

---

Nitpick comments:
In `@Frontend/src/Screens/CalendarScreen.jsx`:
- Around line 332-333: Move the two static values out of the CalendarScreen
component to module-level constants so they are not recreated on each render:
lift timeSlotHeight and SCHEDULE_OFFSET_MINUTES to the top of the file (module
scope) and remove their declarations from inside CalendarScreen; also verify and
correct the offset value—if the time grid starts at 8:00 AM (480 minutes) then
SCHEDULE_OFFSET_MINUTES should reflect that (e.g., 480) or be computed from an
existing scheduleStartMinutes constant to ensure vertical alignment of
appointments.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx`:
- Line 2: Remove the unused Image import and the unused contactImage style:
delete "Image" from the import list in EmergencyCallingScreen.jsx and remove the
contactImage entry from the StyleSheet (or any references to it) so there are no
dead imports or styles left (look for the imported symbol Image and the
StyleSheet key contactImage).
- Line 2: The import list in EmergencyCallingScreen.jsx includes an unused
symbol Platform; remove Platform from the import statement (the line importing
View, Text, TouchableOpacity, StyleSheet, Image, Alert, Linking, Platform) so
only used modules remain to eliminate the unused import warning.

In `@Frontend/src/Screens/SettingsScreen.jsx`:
- Line 1: Remove or update the stale header comment referencing
src/components/ProfileScreen.js in SettingsScreen.jsx; locate the top-of-file
comment (the line containing "// src/components/ProfileScreen.js") and either
delete it or replace it with an accurate comment such as the current
file/component name (e.g., "// src/Screens/SettingsScreen.jsx" or "//
SettingsScreen component") so the file header accurately reflects the file and
component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b90a2535-a0c6-4a0a-b164-753c3a75a071

📥 Commits

Reviewing files that changed from the base of the PR and between 1c60caf and e937788.

📒 Files selected for processing (8)
  • Backend/db/db.py
  • Frontend/src/Screens/CalendarScreen.jsx
  • Frontend/src/Screens/EmergencyCallingScreen.jsx
  • Frontend/src/Screens/HomeScreen.jsx
  • Frontend/src/Screens/ProfileScreen.jsx
  • Frontend/src/Screens/SOSAlertScreen.jsx
  • Frontend/src/Screens/SettingsScreen.jsx
  • Frontend/src/hooks/useChatEngine.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • Frontend/src/hooks/useChatEngine.js

Backend/db/db.py Outdated
@@ -1,9 +1,12 @@
import sqlite3
import os
import fcntl
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Confirm POSIX-only locking usage locations
rg -n -C2 '\bimport\s+fcntl\b|\bfcntl\.flock\s*\(' --type=py

# Check whether project runtime/docs/CI explicitly constrain OS to Linux
fd -HI 'Dockerfile|docker-compose|README|requirements|pyproject|workflows|\.yml|\.yaml' \
  | xargs -r rg -n -C1 'linux|ubuntu|windows|macos|docker|container'

Repository: AOSSIE-Org/BabyNest

Length of output: 5611


🏁 Script executed:

# Check the full context around fcntl usage in db.py
cat -n Backend/db/db.py | head -50

Repository: AOSSIE-Org/BabyNest

Length of output: 1660


🏁 Script executed:

# Look for any platform checks or try/except around fcntl
rg -A5 -B5 'fcntl\.flock' Backend/db/db.py

Repository: AOSSIE-Org/BabyNest

Length of output: 824


🏁 Script executed:

# Search for README and documentation files
fd -HI 'README|CONTRIBUTING|INSTALL|SETUP' | head -20

Repository: AOSSIE-Org/BabyNest

Length of output: 139


🏁 Script executed:

# Look for CI configuration files
fd -HI '\.github|\.gitlab-ci|\.circleci|\.travis|azure-pipelines|Jenkinsfile'

Repository: AOSSIE-Org/BabyNest

Length of output: 71


🏁 Script executed:

# Read main README
cat README.md

Repository: AOSSIE-Org/BabyNest

Length of output: 5067


🏁 Script executed:

# Find and read CI workflow files
fd -HI '\.yml|\.yaml' .github/workflows

Repository: AOSSIE-Org/BabyNest

Length of output: 167


🏁 Script executed:

# Check for any sys.platform guards in the codebase
rg 'sys\.platform|sys\.version_info|os\.name' --type=py -n

Repository: AOSSIE-Org/BabyNest

Length of output: 45


🏁 Script executed:

# Check if Windows is mentioned anywhere in project setup/docs
rg -i 'windows|win32' README.md Backend/ --type=py --type=md

Repository: AOSSIE-Org/BabyNest

Length of output: 45


🏁 Script executed:

# Double-check: are there any platform-specific imports or guards anywhere?
rg -n 'import.*os\.|import sys|try:|except.*ImportError|except.*AttributeError' Backend/db/ --type=py -A2 -B2

Repository: AOSSIE-Org/BabyNest

Length of output: 417


🏁 Script executed:

# Check if there are any conditional imports or fallbacks for fcntl
rg -n 'fcntl|flock' Backend/ --type=py

Repository: AOSSIE-Org/BabyNest

Length of output: 260


Add cross-platform file locking or document Linux-only support.

The fcntl module will fail on Windows (AttributeError on import). Either implement a cross-platform locking fallback using msvcrt on Windows and fcntl on POSIX, or explicitly document and enforce Linux/POSIX-only support in the project README and CI configuration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/db/db.py` at line 3, The code currently imports fcntl (in
Backend/db/db.py) which breaks on Windows; either add a cross-platform fallback
or document POSIX-only support: implement a small compatibility layer that tries
"import fcntl" and on ImportError/import failure imports "msvcrt" and exposes
the same file-locking API (e.g., provide lock_file/unlock_file functions or a
FileLock class used by any existing callers) mapping fcntl.flock semantics to
msvcrt.locking, or if you choose POSIX-only, update the README/CI to state and
enforce Linux/POSIX support and raise a clear RuntimeError at import time if
fcntl is unavailable. Ensure the symbols referenced (fcntl, msvcrt,
lock_file/unlock_file or FileLock) are used consistently so callers in this
module don't need to change.

db.close()

def first_time_setup():
if not os.path.exists(DATABASE) or os.stat(DATABASE).st_size == 0:
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

Harden the database existence check against TOCTOU failures.

Line 24 and Line 31 use exists() + stat() separately; if the file disappears between those calls, startup can throw FileNotFoundError. Use a single race-safe helper and reuse it in both checks.

Proposed fix
+def _db_missing_or_empty(path):
+    try:
+        return os.stat(path).st_size == 0
+    except FileNotFoundError:
+        return True
+
 def first_time_setup():
-    if not os.path.exists(DATABASE) or os.stat(DATABASE).st_size == 0:
+    if _db_missing_or_empty(DATABASE):
         # Use file lock to prevent race condition during setup
         os.makedirs(os.path.dirname(SETUP_LOCK_FILE), exist_ok=True)
         with open(SETUP_LOCK_FILE, 'w') as lock_file:
             try:
                 fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
                 # Double-check after acquiring lock
-                if not os.path.exists(DATABASE) or os.stat(DATABASE).st_size == 0:
+                if _db_missing_or_empty(DATABASE):
                     with sqlite3.connect(DATABASE) as db:
                         with open(SCHEMA_FILE,"r") as f:
                             db.executescript(f.read())
                         db.commit()
             finally:
                 fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)

Also applies to: 31-31

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/db/db.py` at line 24, Replace the two separate exists()+stat() checks
with a single race-safe helper (e.g., file_missing_or_empty(path) or
is_database_missing_or_empty(path)) that performs a single os.stat() call inside
a try/except FileNotFoundError and returns True if the file is missing or its
st_size == 0; then call that helper wherever the code currently uses
os.path.exists(DATABASE) or os.stat(DATABASE).st_size checks (reference the
DATABASE variable and replace both occurrences around the startup checks) so the
check is atomic and TOCTOU-safe.

Comment on lines +12 to +30
const handleEmergencyCall = () => {
setIsCalling(true);
Alert.alert(
'Emergency Call',
`Calling ${EMERGENCY_NUMBER}...`,
[
{ text: 'Cancel', style: 'cancel', onPress: () => setIsCalling(false) },
{
text: 'Call',
onPress: () => {
Linking.openURL(`tel:${EMERGENCY_NUMBER}`).catch(err => {
Alert.alert('Error', 'Unable to make phone call');
setIsCalling(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

Missing state reset after successful call.

When Linking.openURL() succeeds, isCalling remains true, leaving the call button permanently disabled when the user returns to the app. Only error and cancel paths reset the state.

🔧 Proposed fix
           text: 'Call', 
           onPress: () => {
-            Linking.openURL(`tel:${EMERGENCY_NUMBER}`).catch(err => {
+            Linking.openURL(`tel:${EMERGENCY_NUMBER}`).then(() => {
+              setIsCalling(false);
+            }).catch(err => {
               Alert.alert('Error', 'Unable to make phone call');
               setIsCalling(false);
             });
           }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleEmergencyCall = () => {
setIsCalling(true);
Alert.alert(
'Emergency Call',
`Calling ${EMERGENCY_NUMBER}...`,
[
{ text: 'Cancel', style: 'cancel', onPress: () => setIsCalling(false) },
{
text: 'Call',
onPress: () => {
Linking.openURL(`tel:${EMERGENCY_NUMBER}`).catch(err => {
Alert.alert('Error', 'Unable to make phone call');
setIsCalling(false);
});
}
}
]
);
};
const handleEmergencyCall = () => {
setIsCalling(true);
Alert.alert(
'Emergency Call',
`Calling ${EMERGENCY_NUMBER}...`,
[
{ text: 'Cancel', style: 'cancel', onPress: () => setIsCalling(false) },
{
text: 'Call',
onPress: () => {
Linking.openURL(`tel:${EMERGENCY_NUMBER}`).then(() => {
setIsCalling(false);
}).catch(err => {
Alert.alert('Error', 'Unable to make phone call');
setIsCalling(false);
});
}
}
]
);
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` around lines 12 - 30, The
handleEmergencyCall function leaves isCalling true when Linking.openURL
succeeds; update the success path so setIsCalling(false) is called after a
successful openURL (e.g., chain a .then(() => setIsCalling(false)) or use
async/await with try/finally around Linking.openURL(`tel:${EMERGENCY_NUMBER}`))
so both success and failure reset isCalling; reference handleEmergencyCall,
setIsCalling, Linking.openURL and EMERGENCY_NUMBER when making the change.

callingText: { fontSize: 20, color: "white", marginBottom: 20 },
callingCircle: { width: 100, height: 100, borderRadius: 50, backgroundColor: "white", justifyContent: "center", alignItems: "center" },
callingContainer: { flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: "#FF6F61", padding: 20 },
callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center' },
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

Critical syntax error: unterminated string literal.

The string "center' has mismatched quotes (starts with ", ends with '), causing a parse error that will break the application.

🐛 Fix the mismatched quotes
-  callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center' },
+  callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center" },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center' },
callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center" },
🧰 Tools
🪛 Biome (2.4.6)

[error] 86-86: unterminated string literal

(parse)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` at line 86, In the
callingText style object (callingText), fix the unterminated string literal for
textAlign by replacing the mismatched `"center'` with a properly quoted string
(e.g., "center" or 'center') so the style reads textAlign: "center" and the file
parses correctly.

Comment on lines +119 to +123
<IconButton
icon="🔔"
label="Notification"
onPress={() => Alert.alert('Notifications', 'Notification settings coming soon!')}
/>
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

onPress prop is not handled by IconButton component.

The IconButton component (lines 19-30) only accepts { icon, label } props and renders a non-interactive View. The onPress handler passed here will be silently ignored, and the notification button won't respond to taps.

Either update IconButton to accept and use onPress, or use a TouchableOpacity wrapper directly.

🐛 Proposed fix: Update IconButton to support onPress
-const IconButton = ({ icon, label }) => {
+const IconButton = ({ icon, label, onPress }) => {
   const { theme } = useTheme();
 
   return (
-    <View style={[styles.iconContainer, { backgroundColor: theme.iconBackground }]}>
+    <TouchableOpacity 
+      style={[styles.iconContainer, { backgroundColor: theme.iconBackground }]}
+      onPress={onPress}
+      disabled={!onPress}
+    >
       <View style={[styles.iconCircle, { backgroundColor: theme.primary }]}>
         <Text style={styles.iconText}>{icon}</Text>
       </View>
       <Text style={[styles.iconLabel, { color: theme.iconText || theme.text}]}>{label}</Text>
-    </View>
+    </TouchableOpacity>
   );
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/SettingsScreen.jsx` around lines 119 - 123, The
IconButton currently ignores the onPress passed from SettingsScreen, so update
the IconButton component to accept an onPress prop and use a touchable container
(e.g., TouchableOpacity or Pressable) instead of a plain View: add onPress to
IconButton's props signature, wrap the rendered content in
TouchableOpacity/Pressable and pass the onPress handler through (also import
TouchableOpacity/Pressable), and preserve existing icon and label rendering so
the Notification button in SettingsScreen will respond to taps.

Comment on lines +11 to +15
const newCount = tapCount + 1;
setTapCount(newCount);
if (newCount >= 4) {
navigation.navigate("EmergencyCalling");
} else {
setTapCount(tapCount + 1);
setTapCount(0);
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

🧩 Analysis chain

🌐 Web query:

In React Native (React 18+), can onPress handlers lose increments when using setState(valueFromClosure) instead of setState(prev => next)? Please cite React docs on batched/asynchronous updates and functional state updates.

💡 Result:

Yes. In React 18+ (including React Native), an onPress handler can “lose” increments if you compute the next state from a stale value captured in the handler’s closure (e.g. setCount(count + 1)) instead of using a functional update (e.g. setCount(c => c + 1)).

Why it happens:

  • State updates are not applied immediately inside the running event handler—calling a setter requests a re-render, but it doesn’t change the state variable value you already have in that handler/closure. So repeated setCount(count + 1) calls in the same handler (or in async work started by the handler) can all enqueue the same “next value,” effectively dropping increments. React’s useState docs explicitly note that an update “does not affect the … variable in your already-running event handler.” [1]
  • React batches updates (and React 18 introduced broader/automatic batching), so multiple updates can be processed together rather than one-by-one immediately, increasing the chance that “value from closure” updates collapse into one. [2] React 18 also documents “automatic batching” more generally. [3]
  • Functional updates are designed for this case: when you want to update based on the previous state, pass an updater function (setCount(c => c + 1)), and React will apply queued updaters in order using the latest queued state. [2]

Rule of thumb for counters/toggles: if the next state depends on the previous state, use setState(prev => next) (functional update), especially in event handlers and any async callbacks triggered by them.

Sources (React docs):

  1. React useState reference (state value in an already-running handler doesn’t change immediately). [1]
  2. “Queueing a Series of State Updates” (batching + functional updater to avoid lost updates). [2]
  3. React 18 blog post (automatic batching in React 18). [3]

[1] (react.dev)
[2] (react.dev)
[3] (react.dev)

Citations:


Use functional state updates to avoid missed taps in SOS trigger.

On lines 11–15, tapCount + 1 uses a closure value that can drop increments under rapid presses when React batches updates. In this emergency flow, that can make the 4-tap threshold unreliable. Use a functional updater so React applies state changes sequentially based on the previous state, not a stale closure value.

🔧 Proposed fix
   const handleTap = () => {
-    const newCount = tapCount + 1;
-    setTapCount(newCount);
-    if (newCount >= 4) {
-      navigation.navigate("EmergencyCalling");
-      setTapCount(0);
-    }
+    setTapCount((prevCount) => {
+      const newCount = prevCount + 1;
+      if (newCount >= 4) {
+        navigation.navigate("EmergencyCalling");
+        return 0;
+      }
+      return newCount;
+    });
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/SOSAlertScreen.jsx` around lines 11 - 15, The tap
counting logic uses a stale closure value (tapCount + 1) which can miss
increments under rapid presses; update the handler to use a functional state
updater with setTapCount(prev => ...) so each increment is based on the latest
state, compute newCount = prev + 1 inside that updater, call
navigation.navigate("EmergencyCalling") when newCount >= 4, and reset the state
to 0 there (otherwise return newCount); update references to
tapCount/setTapCount and keep the EmergencyCalling navigation call inside the
functional updater.

- vector_store.py: chromadb is now optional, graceful fallback if not installed
- db.py: simplified first_time_setup without file lock (Windows compatibility)
- SOSAlertScreen: removed unused Image import
- EmergencyCallingScreen: removed unused Platform import
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
Backend/agent/vector_store.py (3)

107-120: ⚠️ Potential issue | 🟠 Major

Missing guard for chromadb availability will cause AttributeError.

Same issue as update_guidelines_in_vector_store: when chromadb is unavailable, user_details_collection is None and .upsert() will crash.

Proposed fix
 def update_user_details_in_vector_store(documents: list = None, ids: list = None, metadatas: list = None):
     """Update user details in the vector store."""
+    if not CHROMADB_AVAILABLE:
+        print("ChromaDB not available, skipping user details update.")
+        return
     if not documents or not ids or not metadatas:
         print("No user detail documents to update.")
         return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/agent/vector_store.py` around lines 107 - 120, The function
update_user_details_in_vector_store currently calls
user_details_collection.upsert without checking whether the Chroma
client/collection exists, causing AttributeError when chromadb is unavailable;
update update_user_details_in_vector_store to check that user_details_collection
is not None (and/or that chroma is enabled) before calling upsert, return early
and log a clear message if the collection is missing, and keep the existing
try/except around the upsert call to handle runtime errors.

47-105: ⚠️ Potential issue | 🟠 Major

Missing guard for chromadb availability will cause AttributeError.

When CHROMADB_AVAILABLE is False, guidelines_collection is None. Calling .count() (line 72), .delete() (line 74), or .add() (line 94) on None will raise AttributeError, crashing the function instead of gracefully degrading.

The callers (initialize_knowledge_base in context.py, refresh_cache_and_embeddings in agent.py) don't guard against this either.

Proposed fix
 def update_guidelines_in_vector_store():
     """Update the vector store with pregnancy guidelines."""
+    if not CHROMADB_AVAILABLE:
+        print("ChromaDB not available, skipping vector store update.")
+        return False
     try:
         guidelines_file = os.path.join(os.path.dirname(__file__), "guidelines.json")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/agent/vector_store.py` around lines 47 - 105,
update_guidelines_in_vector_store currently assumes chromadb is available and
calls methods on guidelines_collection which may be None when CHROMADB_AVAILABLE
is False; add a guard at the start of update_guidelines_in_vector_store that
checks CHROMADB_AVAILABLE and that guidelines_collection is not None and return
False (or skip processing) if unavailable, and update callers
initialize_knowledge_base and refresh_cache_and_embeddings to handle a False
return gracefully; ensure all uses of guidelines_collection (count, delete, add)
are only invoked after this guard so AttributeError is avoided.

122-136: ⚠️ Potential issue | 🟠 Major

Missing guard for chromadb availability will cause AttributeError.

Same issue: guidelines_collection.query() will crash when chromadb is unavailable.

Proposed fix
 def query_vector_store(query: str, n_results: int = 3):
     """Query the vector store for relevant guidelines."""
+    if not CHROMADB_AVAILABLE:
+        print("ChromaDB not available, cannot query vector store.")
+        return []
     try:
         results = guidelines_collection.query(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/agent/vector_store.py` around lines 122 - 136, The function
query_vector_store should guard against chromadb being unavailable by checking
that guidelines_collection exists and has a callable query method before calling
guidelines_collection.query; update query_vector_store to verify
guidelines_collection is not None and hasattr(guidelines_collection, "query")
and callable(guidelines_collection.query), log/print a clear message and return
an empty list if the guard fails, then proceed to call
guidelines_collection.query and keep the existing try/except to handle runtime
errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Backend/db/db.py`:
- Line 3: Remove the unused top-level import of the sys module in
Backend/db/db.py (the "import sys" statement); delete that line so no unused
symbol "sys" remains imported and ensure no other references to sys exist in
functions or classes in this file (e.g., any uses in db-related functions or
classes).

---

Outside diff comments:
In `@Backend/agent/vector_store.py`:
- Around line 107-120: The function update_user_details_in_vector_store
currently calls user_details_collection.upsert without checking whether the
Chroma client/collection exists, causing AttributeError when chromadb is
unavailable; update update_user_details_in_vector_store to check that
user_details_collection is not None (and/or that chroma is enabled) before
calling upsert, return early and log a clear message if the collection is
missing, and keep the existing try/except around the upsert call to handle
runtime errors.
- Around line 47-105: update_guidelines_in_vector_store currently assumes
chromadb is available and calls methods on guidelines_collection which may be
None when CHROMADB_AVAILABLE is False; add a guard at the start of
update_guidelines_in_vector_store that checks CHROMADB_AVAILABLE and that
guidelines_collection is not None and return False (or skip processing) if
unavailable, and update callers initialize_knowledge_base and
refresh_cache_and_embeddings to handle a False return gracefully; ensure all
uses of guidelines_collection (count, delete, add) are only invoked after this
guard so AttributeError is avoided.
- Around line 122-136: The function query_vector_store should guard against
chromadb being unavailable by checking that guidelines_collection exists and has
a callable query method before calling guidelines_collection.query; update
query_vector_store to verify guidelines_collection is not None and
hasattr(guidelines_collection, "query") and
callable(guidelines_collection.query), log/print a clear message and return an
empty list if the guard fails, then proceed to call guidelines_collection.query
and keep the existing try/except to handle runtime errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 030858c6-0354-45b3-b8af-32d55e03efbc

📥 Commits

Reviewing files that changed from the base of the PR and between e937788 and 8c12e6c.

📒 Files selected for processing (2)
  • Backend/agent/vector_store.py
  • Backend/db/db.py

@@ -1,9 +1,11 @@
import sqlite3
import os
import sys
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 | 🟡 Minor

Remove unused sys import.

The sys module is imported but never used in this file.

Proposed fix
 import sqlite3
 import os
-import sys
 from flask import g
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/db/db.py` at line 3, Remove the unused top-level import of the sys
module in Backend/db/db.py (the "import sys" statement); delete that line so no
unused symbol "sys" remains imported and ensure no other references to sys exist
in functions or classes in this file (e.g., any uses in db-related functions or
classes).

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.

♻️ Duplicate comments (3)
Frontend/src/Screens/EmergencyCallingScreen.jsx (2)

22-25: ⚠️ Potential issue | 🟠 Major

Reset isCalling on successful dial open as well.

Line [22] only resets state on failure. After a successful Linking.openURL, isCalling can stay true, leaving the call control disabled when user returns. This repeats the previously reported issue.

🔧 Proposed fix
         { 
           text: 'Call', 
-          onPress: () => {
-            Linking.openURL(`tel:${EMERGENCY_NUMBER}`).catch(err => {
-              Alert.alert('Error', 'Unable to make phone call');
-              setIsCalling(false);
-            });
+          onPress: async () => {
+            try {
+              await Linking.openURL(`tel:${EMERGENCY_NUMBER}`);
+            } catch (err) {
+              Alert.alert('Error', 'Unable to make phone call');
+            } finally {
+              setIsCalling(false);
+            }
           }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` around lines 22 - 25, The
on-call opener only resets state on failure; ensure isCalling is reset after a
successful dial as well by handling the Promise returned by Linking.openURL (for
the call to `tel:${EMERGENCY_NUMBER}`) and invoking `setIsCalling(false)` on
success (or in a `.finally()`/resolved handler) so the UI is re-enabled when the
user returns; locate the existing `Linking.openURL(...).catch(...)` call and add
the success/final handler to clear `isCalling`.

86-87: ⚠️ Potential issue | 🔴 Critical

Fix unterminated string literal in styles (parse blocker).

Line [86] has mismatched quotes in textAlign, which breaks parsing and causes the Line [87] comma error downstream. This repeats the previously reported issue.

🐛 Proposed fix
-  callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center' },
+  callingText: { fontSize: 22, color: "white", marginBottom: 30, fontWeight: "bold", textAlign: "center" },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/EmergencyCallingScreen.jsx` around lines 86 - 87, The
style object callingText has a mismatched quote in the textAlign property
causing a parse error; open the styles where callingText and instructionText are
defined and fix textAlign in callingText to use matching quotes (e.g.,
textAlign: "center") so the object literal is valid and the trailing comma after
instructionText no longer triggers a downstream error.
Frontend/src/Screens/SOSAlertScreen.jsx (1)

11-15: ⚠️ Potential issue | 🟠 Major

Use functional state updates for the SOS tap counter.

Line [11] reads tapCount from closure, which can miss increments under batched/rapid taps and make the 4-tap trigger unreliable. This repeats the previously reported issue.

🔧 Proposed fix
   const handleTap = () => {
-    const newCount = tapCount + 1;
-    setTapCount(newCount);
-    if (newCount >= 4) {
-      navigation.navigate("EmergencyCalling");
-      setTapCount(0);
-    }
+    setTapCount((prevCount) => {
+      const newCount = prevCount + 1;
+      if (newCount >= 4) {
+        navigation.navigate("EmergencyCalling");
+        return 0;
+      }
+      return newCount;
+    });
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Frontend/src/Screens/SOSAlertScreen.jsx` around lines 11 - 15, The tap
counter uses the stale closure variable tapCount when calling setTapCount,
causing missed increments under rapid taps; change to a functional state update
with setTapCount(prev => { const newCount = prev + 1; if (newCount >= 4) {
navigation.navigate("EmergencyCalling"); return 0; } return newCount; }) so
increments are based on the latest state and the 4-tap trigger is reliable
(refer to tapCount, setTapCount, and navigation.navigate("EmergencyCalling")).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Frontend/src/Screens/EmergencyCallingScreen.jsx`:
- Around line 22-25: The on-call opener only resets state on failure; ensure
isCalling is reset after a successful dial as well by handling the Promise
returned by Linking.openURL (for the call to `tel:${EMERGENCY_NUMBER}`) and
invoking `setIsCalling(false)` on success (or in a `.finally()`/resolved
handler) so the UI is re-enabled when the user returns; locate the existing
`Linking.openURL(...).catch(...)` call and add the success/final handler to
clear `isCalling`.
- Around line 86-87: The style object callingText has a mismatched quote in the
textAlign property causing a parse error; open the styles where callingText and
instructionText are defined and fix textAlign in callingText to use matching
quotes (e.g., textAlign: "center") so the object literal is valid and the
trailing comma after instructionText no longer triggers a downstream error.

In `@Frontend/src/Screens/SOSAlertScreen.jsx`:
- Around line 11-15: The tap counter uses the stale closure variable tapCount
when calling setTapCount, causing missed increments under rapid taps; change to
a functional state update with setTapCount(prev => { const newCount = prev + 1;
if (newCount >= 4) { navigation.navigate("EmergencyCalling"); return 0; } return
newCount; }) so increments are based on the latest state and the 4-tap trigger
is reliable (refer to tapCount, setTapCount, and
navigation.navigate("EmergencyCalling")).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4f96072a-040f-45c5-87d9-b89c0ff610d6

📥 Commits

Reviewing files that changed from the base of the PR and between 8c12e6c and 80c3f25.

📒 Files selected for processing (2)
  • Frontend/src/Screens/EmergencyCallingScreen.jsx
  • Frontend/src/Screens/SOSAlertScreen.jsx

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