Skip to content

refactor: extract shared utilities from duplicated code patterns#2

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1780488315-refactor-shared-utilities
Open

refactor: extract shared utilities from duplicated code patterns#2
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1780488315-refactor-shared-utilities

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Eliminates duplicated code across backend controllers, middleware, and frontend by extracting shared utilities. All 100 existing tests pass.

Backend — three new modules replace repeated inline patterns across all controllers and middleware:

  • utils/response.jssendSuccess(res, code, msg, data) / sendError(res, code, msg) replaces every manual res.status().json({ success, message }) call (~15 occurrences across auth.controller, ticket.controller, auth middleware, and app.js)
  • utils/catchAsync.js → wraps async handlers with configurable error messages, eliminating duplicated try/catch + console.error + 500-response boilerplate in every controller (5 handlers)
  • middleware/validate.jsvalidateFields(fields) route-level middleware for declarative field validation

Refactored files: auth.controller.js, ticket.controller.js, auth.routes.js, ticket.routes.js, middleware/auth.js, app.js

Frontend — reusable IconLink component:

  • components/IconLink.jsx extracts the repeated <li><a><svg|img>...</a></li> pattern (6 occurrences → 1 component + declarative socialLinks array)
  • App.jsx: 122 → 75 lines

Link to Devin session: https://app.devin.ai/sessions/8015016401f24d2698c63a0bddf8495d
Requested by: @0xpritam

Summary by CodeRabbit

  • New Features

    • Request body validation added for registration, login, and ticket creation to ensure required fields are present.
    • Centralized success/error responses across the API for consistent messages.
  • Bug Fixes

    • Auth and ticket endpoints now return unified error responses for missing/invalid credentials and unauthorized access.
  • UI/Style

    • Refactored external documentation and social links into a reusable link component.
  • Chores

    • Added a stable unique ID dependency for ticket generation.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 47fd9d08-4fc1-416c-be30-b75e2603db35

📥 Commits

Reviewing files that changed from the base of the PR and between f7d4d1c and 8838b3b.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • backend/package.json
✅ Files skipped from review due to trivial changes (1)
  • backend/package.json

📝 Walkthrough

Walkthrough

Adds standardized response helpers and an async wrapper, a request validation middleware, integrates them into auth and ticket controllers/routes and the health endpoint; extracts a reusable IconLink component and updates App.jsx to render documentation and social links with it.

Changes

Backend Error Handling & Auth Refactoring

Layer / File(s) Summary
Response helper functions
backend/src/utils/response.js
sendSuccess and sendError utilities provide consistent JSON response formatting with status code, message, and optional merged data.
Async error wrapper
backend/src/utils/catchAsync.js
catchAsync middleware wraps async handlers, catches rejections, logs the handler name, and responds with standardized 500 errors.
Request validation middleware
backend/src/middleware/validate.js
validateFields factory returns middleware that inspects required fields in req.body, responds with 400 and missing field names on failure, or calls next() on success.
Auth controller and route integration
backend/src/controllers/auth.controller.js, backend/src/routes/auth.routes.js, backend/src/app.js
register and login controllers are refactored to use catchAsync and standardized response helpers; routes are wired with validateFields for registration (name/email/password) and login (email/password) validation; app health endpoint uses sendSuccess.
Auth middleware
backend/src/middleware/auth.js
authenticate now uses sendError for missing/invalid token responses instead of inline JSON construction.
Ticket controllers and routes
backend/src/controllers/ticket.controller.js, backend/src/routes/ticket.routes.js
Ticket handlers (generateTicket, getMyTickets, getTicketById) now use catchAsync and sendSuccess/sendError; POST /api/tickets is validated with validateFields(['departmentId']).

Frontend Link Component Extraction

Layer / File(s) Summary
IconLink component
frontend/src/components/IconLink.jsx
New component renders list item with anchor link and conditionally displays icon as <img> or SVG <use> sprite reference based on icon string format.
App link refactoring
frontend/src/App.jsx
Adds socialLinks data array with href/icon/label; replaces hardcoded documentation and social links markup with dynamic IconLink rendering via .map().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 0xpritam/SmartQueue#7: Refactors Ticket API code and is closely related to the controller/route changes in this PR.

Poem

🐰 I hopped through handlers, tidy and spry,
Wrapped errors in blankets, responses ran high,
Icons stitched neatly, links take flight,
Backend and frontend gleam in the light,
A little rabbit claps — code feels right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: extract shared utilities from duplicated code patterns' directly and accurately summarizes the main objective of this PR, which is extracting and consolidating repeated code patterns across backend utilities, controllers, middleware, and frontend components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1780488315-refactor-shared-utilities

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
frontend/src/App.jsx (2)

62-64: ⚡ Quick win

Prefer a stable key over label.

Using link.label as the React key works since labels are currently unique, but it's fragile—if labels change for internationalization or become non-unique, React's reconciliation will break. Use link.href (guaranteed unique per destination) or the array index instead.

♻️ Proposed refactor
-            {socialLinks.map((link) => (
-              <IconLink key={link.label} {...link} />
+            {socialLinks.map((link) => (
+              <IconLink key={link.href} {...link} />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.jsx` around lines 62 - 64, The React list is using
link.label as the key in the socialLinks.map when rendering <IconLink>, which is
fragile; change the key to a stable unique identifier such as link.href (or
fallback to the array index) by updating the map callback to use key={link.href}
(or key={i} if you must) so IconLink renders with a stable unique key.

8-13: SVG sprite icon IDs are present; minor key stability tweak

  • frontend/public/icons.svg defines github-icon, discord-icon, x-icon, and bluesky-icon, so the social link icons should render correctly.
  • In frontend/src/App.jsx, use a more stable React key than link.label for socialLinks.map (e.g., href).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.jsx` around lines 8 - 13, The socialLinks array in
frontend/src/App.jsx is mapped to render icons using SVG IDs but the React list
key uses link.label which can be unstable; update the map in the component that
iterates socialLinks (the socialLinks.map callback) to use a more stable unique
key such as link.href (or another unique identifier) instead of link.label so
React list reconciliation is reliable.
backend/src/utils/catchAsync.js (1)

3-8: ⚡ Quick win

Guard against res.headersSent before sending the 500.

If a wrapped handler throws after it has already started/sent a response, the .catch will attempt a second write through sendError, triggering ERR_HTTP_HEADERS_SENT and masking the original error. Forward to Express in that case.

♻️ Proposed guard
 const catchAsync = (fn) => (req, res, next) => {
   Promise.resolve(fn(req, res, next)).catch((error) => {
     console.error(`${fn.name || 'Handler'} error:`, error);
+    if (res.headersSent) {
+      return next(error);
+    }
     sendError(res, 500, 'An internal server error occurred.');
   });
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/utils/catchAsync.js` around lines 3 - 8, The catchAsync wrapper
should check res.headersSent before calling sendError to avoid writing headers
twice; modify catchAsync (the Promise.resolve(...).catch block) to, on error,
log the error as it currently does and then if res.headersSent call next(error)
to forward to Express, otherwise call sendError(res, 500, 'An internal server
error occurred.'); ensure you reference the existing fn (handler) and next
parameters so the error is forwarded when headers were already sent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/middleware/validate.js`:
- Line 4: The validation currently does requiredFields.filter((field) =>
!req.body[field]) and will throw if req.body is undefined; change the middleware
(the validate function/middleware where requiredFields.filter is used) to guard
by defaulting req.body to an empty object (e.g., const body = req.body || {})
and use body[field] in the filter so missing/empty request bodies return the
expected 400 instead of causing a 500.

In `@frontend/src/components/IconLink.jsx`:
- Line 5: The anchor in IconLink.jsx opens external links with target="_blank"
but omits rel attributes; update the <a> element used in the IconLink component
to include rel="noopener noreferrer" alongside target="_blank" (ensuring this is
applied wherever the component renders the anchor and when props.href points to
external URLs) so you prevent window.opener tabnabbing and referrer leakage.

---

Nitpick comments:
In `@backend/src/utils/catchAsync.js`:
- Around line 3-8: The catchAsync wrapper should check res.headersSent before
calling sendError to avoid writing headers twice; modify catchAsync (the
Promise.resolve(...).catch block) to, on error, log the error as it currently
does and then if res.headersSent call next(error) to forward to Express,
otherwise call sendError(res, 500, 'An internal server error occurred.'); ensure
you reference the existing fn (handler) and next parameters so the error is
forwarded when headers were already sent.

In `@frontend/src/App.jsx`:
- Around line 62-64: The React list is using link.label as the key in the
socialLinks.map when rendering <IconLink>, which is fragile; change the key to a
stable unique identifier such as link.href (or fallback to the array index) by
updating the map callback to use key={link.href} (or key={i} if you must) so
IconLink renders with a stable unique key.
- Around line 8-13: The socialLinks array in frontend/src/App.jsx is mapped to
render icons using SVG IDs but the React list key uses link.label which can be
unstable; update the map in the component that iterates socialLinks (the
socialLinks.map callback) to use a more stable unique key such as link.href (or
another unique identifier) instead of link.label so React list reconciliation is
reliable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ab811171-f143-4df0-aa74-db9eb7cbdcdc

📥 Commits

Reviewing files that changed from the base of the PR and between 44f8626 and dc5f697.

📒 Files selected for processing (8)
  • backend/src/app.js
  • backend/src/controllers/auth.controller.js
  • backend/src/middleware/validate.js
  • backend/src/routes/auth.routes.js
  • backend/src/utils/catchAsync.js
  • backend/src/utils/response.js
  • frontend/src/App.jsx
  • frontend/src/components/IconLink.jsx

Comment thread backend/src/middleware/validate.js Outdated
Comment thread frontend/src/components/IconLink.jsx Outdated
Backend:
- Add utils/response.js (sendSuccess, sendError) to centralize API responses
- Add utils/catchAsync.js to eliminate duplicated try-catch error handling
- Add middleware/validate.js (validateFields) to DRY input validation
- Refactor auth.controller.js and auth.routes.js to use shared utilities
- Refactor app.js health check to use response utility

Frontend:
- Add components/IconLink.jsx for reusable icon+link pattern
- Refactor App.jsx to use IconLink component, removing 6 repetitive blocks
- Extract social links data into a declarative array

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1780488315-refactor-shared-utilities branch from dc5f697 to a72b181 Compare June 4, 2026 17:43
- Guard against undefined req.body in validateFields middleware
- Add rel='noopener noreferrer' to IconLink for security
- Use link.href as stable React key instead of link.label

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Addressed all CodeRabbit feedback in f7d4d1c:

  • validate.js: Guard against undefined req.body
  • IconLink.jsx: Added rel="noopener noreferrer" for security
  • App.jsx: Switched React key from link.label to link.href for stability

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/controllers/ticket.controller.js`:
- Line 2: Add 'uuid' as a direct runtime dependency in backend/package.json
because ticket.controller.js requires it (const { v4: uuidv4 } =
require('uuid')). Update the "dependencies" section to include "uuid" (pick a
compatible semver, e.g. ^8.3.2 or the latest stable), then run the package
manager (npm install --save uuid or yarn add uuid) to update package-lock.json;
this ensures require('uuid') in ticket.controller.js will always resolve.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6011cb32-7989-431e-b6f4-ed141f9cd8a1

📥 Commits

Reviewing files that changed from the base of the PR and between dc5f697 and f7d4d1c.

📒 Files selected for processing (11)
  • backend/src/app.js
  • backend/src/controllers/auth.controller.js
  • backend/src/controllers/ticket.controller.js
  • backend/src/middleware/auth.js
  • backend/src/middleware/validate.js
  • backend/src/routes/auth.routes.js
  • backend/src/routes/ticket.routes.js
  • backend/src/utils/catchAsync.js
  • backend/src/utils/response.js
  • frontend/src/App.jsx
  • frontend/src/components/IconLink.jsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/src/utils/catchAsync.js
  • backend/src/utils/response.js
  • backend/src/middleware/validate.js
  • frontend/src/App.jsx
  • backend/src/routes/auth.routes.js

Comment thread backend/src/controllers/ticket.controller.js
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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