Skip to content

refactor: update AsyncQueueManager to use a single RabbitMQ priority queue and enhance connection handling; add default queue name and priority mapping#256

Closed
vaishcodescape wants to merge 8 commits intoAOSSIE-Org:mainfrom
vaishcodescape:aditya/single-queue-refactor
Closed

Conversation

@vaishcodescape
Copy link

@vaishcodescape vaishcodescape commented Jan 29, 2026

Pull Request

Closes #251

📝 Description

Refactors AsyncQueueManager to fix inefficient queue polling and make it production-ready. Replaces three separate queues (high_task_queue, medium_task_queue, low_task_queue) with a single RabbitMQ priority queue and push-based consumption. Workers no longer poll with queue.get() and a fixed sleep; priority is enforced by the broker via x-max-priority and per-message priority, and workers use queue.iterator() so the broker pushes messages instead of the app polling.

🔧 Changes Made

  • Single priority queue: Replaced three queues with one queue (task_queue) declared with x-max-priority: 10. All messages go to this queue with a numeric priority (HIGH=10, MEDIUM=5, LOW=1).
  • Push-based workers: Workers no longer loop over queues and call queue.get(). Each worker uses async with queue.iterator(): async for message in queue_iter so the broker pushes messages; no polling or asyncio.sleep(0.1).
  • Prefetch (QoS): Set channel.set_qos(prefetch_count=1) so the broker doesn’t over-deliver; each consumer has at most one unacked message.
  • Publishing: enqueue() publishes to the single queue with aio_pika.Message(..., priority=numeric_priority) and the same routing_key. Public API unchanged: enqueue(message, priority=QueuePriority.MEDIUM, delay=0).
  • Shutdown: stop() clears worker_tasks after gather and closes channel/connection. Workers break out of the iterator when cancelled or when self.running is False.

📷 Screenshots or Visual Changes (if applicable)

N/A

🤝 Collaboration

✅ Checklist

N/A

  • I have read the contributing guidelines.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added necessary documentation (if applicable).
  • Any dependent changes have been merged and published in downstream modules.

Summary by CodeRabbit

Release Notes

  • New Features

    • Redesigned landing page with enhanced UI components and animations
    • Improved navigation with smooth scrolling to page sections
    • Enriched footer with social links, quick navigation, and back-to-top functionality
    • Upgraded waitlist signup form with improved user experience
  • Style

    • Updated design system with expanded color palette and typography scale
    • Added decorative animations and visual effects throughout landing page

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

…nce Tailwind CSS configuration for improved styling
…ist sections with improved styling and functionality
…onents with QuickLink for improved hash navigation, and update Waitlist component for type safety
…default behavior in handleSmoothScroll function in Navbar
…queue and enhance connection handling; add default queue name and priority mapping
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

This PR introduces a major backend queue architecture refactoring and comprehensive landing page redesign. The backend replaces inefficient polling-based multi-queue system with a single RabbitMQ priority queue using push-based consumption. The landing pages are redesigned with Material-UI components, new CSS design tokens, and animated interactive elements including updated navigation, footer, hero section, and waitlist form, alongside new dependencies and a custom Button component.

Changes

Cohort / File(s) Summary
Backend Queue Architecture
backend/app/core/orchestration/queue_manager.py
Refactored AsyncQueueManager from polling multiple per-priority queues to single RabbitMQ priority queue with push-based long-lived consumer. Added PRIORITY_MAP for numeric priority mapping, updated connect/start/stop lifecycle methods with explicit return types, rewrote _worker() as async iterator-based consumer with proper cancellation, and introduced _process_item() for explicit message-type routing with async/sync handler support.
Frontend Export Updates
frontend/src/components/pages/index.ts
Removed four re-export statements for Dashboard, BotIntegrationPage, ContributorsPage, and PullRequestsPage, requiring direct imports from source paths.
Landing Dependencies & Base Styling
landing/package.json, landing/src/index.css, landing/tailwind.config.js
Added @emotion/react, @emotion/styled, @mui/icons-material, @mui/material dependencies. Extended CSS with design tokens (colors, shadows, spacing, radii), comprehensive typography scale, elevation/interaction utilities, animation definitions, and Tailwind theme expansion with new color variants, font sizes, and shadow presets.
Landing Layout Components
landing/src/components/layout/Footer.tsx, landing/src/components/layout/Navbar.tsx
Converted Footer from static HTML to feature-rich MUI implementation with Framer Motion animations, internal routing via useNavigate for hash-style navigation, social icons, legal links, and decorative backgrounds. Updated Navbar with smooth scroll handling, gradient-styled branding, and consistent use of handleSmoothScroll for all navigation links.
Landing Section Components
landing/src/components/sections/Hero.tsx, landing/src/components/sections/Waitlist.tsx
Converted Hero section from legacy markup to MUI Box/Container layout with Typography, Chips, Buttons, enhanced with gradient text and decorative visual layers. Rewrote Waitlist form with MUI TextField/Select components, improved state management (role, submitted), Paper-based confirmation UI, enhanced submit button with loading states and gradient styling, and consolidated error handling with toast notifications.
Landing UI Components
landing/src/components/ui/Button.tsx
New reusable Button component with tailored Tailwind styles, support for primary/secondary variants, optional startIcon/endIcon, responsive fullWidth option, Framer Motion animations, and accessibility attributes (aria-disabled, proper tab handling).

Sequence Diagram

sequenceDiagram
    actor Client
    participant Manager as AsyncQueueManager
    participant RabbitMQ as RabbitMQ<br/>(Single Priority Queue)
    participant Worker1 as Worker 1
    participant Handler as Message Handler

    Note over Client,Handler: Old Flow (Polling-Based)
    Client->>Manager: enqueue(msg, priority=HIGH)
    Manager->>RabbitMQ: publish to HIGH_QUEUE
    Worker1->>Worker1: sleep(0.1)
    Worker1->>RabbitMQ: poll HIGH_QUEUE
    Worker1->>RabbitMQ: poll MEDIUM_QUEUE
    Worker1->>RabbitMQ: poll LOW_QUEUE
    RabbitMQ-->>Worker1: message (if available)
    
    Note over Client,Handler: New Flow (Push-Based)
    Client->>Manager: enqueue(msg, priority=HIGH)
    Manager->>RabbitMQ: publish to queue<br/>with priority=10
    Worker1->>RabbitMQ: await queue.iterator()
    RabbitMQ-->>Worker1: push message immediately
    Worker1->>Manager: _process_item(msg)
    Manager->>Handler: call async/sync handler
    Handler-->>Manager: result
    Manager->>RabbitMQ: ack message
    RabbitMQ-->>Worker1: ready for next message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #88: Both modify backend/app/core/orchestration/queue_manager.py with overlapping changes to AsyncQueueManager methods (connect, start, stop, enqueue, _worker, _process_item), replacing in-memory queues with RabbitMQ-based logic.
  • PR #113: Both modify landing footer and waitlist components (landing/src/components/layout/Footer.tsx, landing/src/components/sections/Waitlist.tsx) with overlapping UI/design changes.
  • PR #76: Both touch the orchestration queue layer; this PR refactors AsyncQueueManager to single priority-queue API while the related PR adds handlers that interact with the new enqueue/clear-memory flows.

Suggested reviewers

  • chandansgowda

Poem

🐰 From polls that wasted precious CPU time,
To push-based queues in RabbitMQ's prime,
The landing pages bloom with Material grace,
New tokens and shadows light up the place!
With buttons that shimmer and footers that glow,
Devr.AI's design steals quite the show! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR contains extensive out-of-scope changes beyond the AsyncQueueManager refactor: UI component rewrites (Footer, Navbar, Hero, Waitlist), new Button component, styling updates (index.css, tailwind.config.js), and dependency additions unrelated to queue optimization. Separate the AsyncQueueManager refactor (backend/app/core/orchestration/queue_manager.py) from frontend/landing changes into distinct PRs. The queue optimization should be reviewed independently from UI enhancements.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the primary code change: transitioning AsyncQueueManager from multiple queues to a single RabbitMQ priority queue with enhanced connection handling.
Linked Issues check ✅ Passed The PR implementation addresses all core requirements from issue #251: replaces polling with push-based consumption via queue iterator, sets QoS with prefetch_count=1, eliminates asyncio.sleep(0.1), uses broker-enforced priority delivery, and implements graceful shutdown via task gathering and cancellation.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

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: 5

Caution

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

⚠️ Outside diff range comments (2)
landing/src/components/sections/Waitlist.tsx (1)

55-104: Trim values before submission to avoid trailing-space data.

You validate with trim() but still submit raw values. This can store whitespace in Google Forms entries.

✅ Suggested fix
-      if (!name.trim() || !email.trim() || !organization.trim() || !role) {
+      const trimmedName = name.trim();
+      const trimmedEmail = email.trim();
+      const trimmedOrganization = organization.trim();
+      const trimmedSuggestions = suggestions.trim();
+
+      if (!trimmedName || !trimmedEmail || !trimmedOrganization || !role) {
         throw new Error('All fields are required except suggestions');
       }

       const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
-      if (!emailRegex.test(email)) {
+      if (!emailRegex.test(trimmedEmail)) {
         throw new Error('Please enter a valid email address');
       }

       const formData = new URLSearchParams();
-      formData.append(FIELD_MAPPINGS.name, name);
-      formData.append(FIELD_MAPPINGS.email, email);
-      formData.append(FIELD_MAPPINGS.organization, organization);
+      formData.append(FIELD_MAPPINGS.name, trimmedName);
+      formData.append(FIELD_MAPPINGS.email, trimmedEmail);
+      formData.append(FIELD_MAPPINGS.organization, trimmedOrganization);
       formData.append(FIELD_MAPPINGS.role, role);
-      if (suggestions) {
-        formData.append(FIELD_MAPPINGS.suggestions, suggestions);
+      if (trimmedSuggestions) {
+        formData.append(FIELD_MAPPINGS.suggestions, trimmedSuggestions);
       }
backend/app/core/orchestration/queue_manager.py (1)

145-165: Propagate handler failures so messages aren’t silently acked.
Exceptions are caught and swallowed, so _worker still acks messages even when processing fails. Re-raise after logging (or return a success flag) so the worker can nack and avoid silent loss.

🐛 Suggested fix
         except Exception as e:
             logger.error(f"Error processing item {item.get('id', 'unknown')}: {str(e)}")
+            raise
🤖 Fix all issues with AI agents
In `@backend/app/core/orchestration/queue_manager.py`:
- Around line 87-109: Guard the enqueue method against an uninitialized or
closed channel by checking self.channel exists and is open before publishing (in
the enqueue function) and raise or log a clear error if not ready; update stop()
to explicitly set self.channel = None (and any related connection state) so
post-shutdown calls hit the guard; reference the enqueue method's use of
self.channel.default_exchange.publish and the stop/connect/start lifecycle
methods to implement these checks and state resets.

In `@landing/package.json`:
- Around line 15-16: Update package.json to pin the react-is package to the
React 18-compatible release so MUI v7 doesn't pull react-is@19; add or update
the dependency resolution settings (use "resolutions" for yarn or "overrides"
for npm >=8.13+) to force "react-is": "18.3.1" alongside your existing
dependencies ("@mui/material" and "@mui/icons-material") and run install to lock
the transitive version.

In `@landing/src/components/layout/Footer.tsx`:
- Around line 28-74: QuickLink is declared inside Footer causing re-creation on
each render; move the QuickLink component definition out of Footer (make it a
top-level component) and update its signature to accept props for navigate and
isHomePage (or obtain navigate via context) so Footer passes navigate and
isHomePage into QuickLink; ensure the prop type remains React.FC<{ link: {
label: string; href: string }; isHomePage: boolean; navigate: (to: string) =>
void }> (or adjust if using context) and update Footer usage to pass the values
accordingly.

In `@landing/src/components/layout/Navbar.tsx`:
- Around line 53-60: Update the misleading comment inside handleSmoothScroll to
match the actual behavior: since e.preventDefault() is called, remove or
rephrase the line that says "Do not prevent default navigation" so it accurately
states that default navigation is prevented, the mobile menu is closed via
setIsOpen(false), and navigation is performed programmatically with
navigate(href) (the scrolling is handled elsewhere by the useEffect). Ensure the
comment references handleSmoothScroll, e.preventDefault(), setIsOpen, and
navigate for clarity.

In `@landing/src/index.css`:
- Around line 142-153: The pseudo-element stacking for buttons is wrong: update
.btn-primary::before and .btn-secondary::before to use z-index: 1 (instead of
-1), ensure any corresponding ::after pseudo-element keeps z-index: 0, and
ensure the button inner content (e.g., the element targeted by .btn-primary
.content or the main button selector) has z-index: 10 so the gradient sits
behind content but above the button background; alternatively, if the Hero
component intentionally uses inline sx overrides for backgroundPosition and you
want to remove the unused animation, delete the ::before/::after
animation/transition rules for .btn-primary/.btn-secondary and rely on the
inline styles used in the Hero component.
🧹 Nitpick comments (5)
landing/src/components/layout/Navbar.tsx (1)

81-91: Consider extracting the brand gradient to a reusable style.

The gradient style for "Devr.AI" is defined inline here and duplicated in Footer.tsx. Consider extracting it to a CSS class in index.css or a shared constant to maintain consistency and reduce duplication.

landing/src/components/layout/Footer.tsx (1)

138-199: Redundant styling: className duplicates sx prop.

Multiple elements define the same styles in both Tailwind className and MUI sx prop (e.g., lines 139-144). Choose one styling approach for consistency and reduced maintenance burden.

Example of redundancy at lines 139-144
// Current: both className and sx define the same styles
<Box
    className="absolute inset-0 pointer-events-none"
    sx={{
        position: 'absolute',
        inset: 0,
        pointerEvents: 'none',
    }}
>

Pick either Tailwind classes or MUI sx prop, not both.

landing/src/components/sections/Hero.tsx (2)

32-45: Avoid duplicate layout sources (className + sx).

Both className and sx define the same layout (minHeight, flex, alignment, padding). Picking one source prevents future drift and style conflicts.

♻️ Suggested cleanup
-        <Box
-            component="section"
-            className="relative min-h-screen flex items-center justify-center pt-32 pb-20 overflow-hidden"
+        <Box
+            component="section"
             sx={{
                 position: 'relative',
                 minHeight: '100vh',
                 display: 'flex',
                 alignItems: 'center',
                 justifyContent: 'center',
                 paddingTop: { xs: 8, md: 16 },
                 paddingBottom: { xs: 5, md: 10 },
                 overflow: 'hidden',
             }}
         >

190-218: Consider display: inline-block for gradient span.

Some browsers handle background-clip on inline text more reliably with inline-block.

🎨 Optional tweak
                         <Box
                             component="span"
                             className="gradient-text"
                             sx={{
+                                display: 'inline-block',
                                 background: 'linear-gradient(to right, `#4ade80`, `#3b82f6`, `#22d3ee`, `#2563eb`, `#10b981`)',
                                 WebkitBackgroundClip: 'text',
                                 WebkitTextFillColor: 'transparent',
                                 backgroundClip: 'text',
                             }}
                         >
landing/src/components/sections/Waitlist.tsx (1)

322-417: Consider extracting shared TextField styles.

The same sx pattern repeats across multiple fields; a shared base style would reduce duplication and ease maintenance.

♻️ Example extraction
+  const baseTextFieldSx = {
+    '& .MuiOutlinedInput-root': {
+      backgroundColor: 'rgba(39, 39, 42, 0.8)',
+      backdropFilter: 'blur(8px)',
+      color: 'white',
+      borderRadius: '12px',
+      border: '1px solid rgba(63, 63, 70, 1)',
+      transition: 'all 0.3s ease',
+      '&:hover': { borderColor: 'rgba(82, 82, 91, 1)' },
+      '& fieldset': { border: 'none' },
+    },
+    '& .MuiInputLabel-root': {
+      color: 'rgba(209, 213, 219, 1)',
+      fontWeight: 600,
+      fontSize: '0.875rem',
+    },
+    '& .MuiInputBase-input': {
+      color: 'white',
+      '&::placeholder': { color: 'rgba(113, 113, 122, 1)', opacity: 1 },
+    },
+  };

Then apply in fields:

-                    <TextField
+                    <TextField
                       id="name"
                       ...
-                      sx={{
-                        '& .MuiOutlinedInput-root': { ... },
-                        '& .MuiInputLabel-root': { ... },
-                        '& .MuiInputBase-input': { ... },
-                      }}
+                      sx={{
+                        ...baseTextFieldSx,
+                        '& .MuiOutlinedInput-root': {
+                          ...baseTextFieldSx['& .MuiOutlinedInput-root'],
+                          '&.Mui-focused': {
+                            borderColor: 'rgba(34, 197, 94, 0.5)',
+                            boxShadow: '0 0 0 2px rgba(34, 197, 94, 0.1)',
+                          },
+                        },
+                        '& .MuiInputLabel-root': {
+                          ...baseTextFieldSx['& .MuiInputLabel-root'],
+                          '&.Mui-focused': { color: 'rgba(34, 197, 94, 1)' },
+                        },
+                      }}
                     />

Comment on lines +87 to 109
async def enqueue(
self,
message: Dict[str, Any],
priority: QueuePriority = QueuePriority.MEDIUM,
delay: float = 0,
) -> None:
"""Add a message to the single priority queue."""
if delay > 0:
await asyncio.sleep(delay)

queue_item = {
"id": message.get("id", f"msg_{datetime.now().timestamp()}"),
"priority": priority,
"data": message
"priority": priority.value,
"data": message,
}
json_message = json.dumps(queue_item).encode()
json_body = json.dumps(queue_item).encode()
numeric_priority = PRIORITY_MAP[priority]

await self.channel.default_exchange.publish(
aio_pika.Message(body=json_message),
routing_key=self.queues[priority]
aio_pika.Message(body=json_body, priority=numeric_priority),
routing_key=self.queue_name,
)
logger.info(f"Enqueued message {queue_item['id']} with priority {priority}")
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 queue_manager.py file and check its full implementation
find . -name "queue_manager.py" -type f

Repository: AOSSIE-Org/Devr.AI

Length of output: 111


🏁 Script executed:

# Read the queue_manager.py file to understand the full context
cat -n backend/app/core/orchestration/queue_manager.py

Repository: AOSSIE-Org/Devr.AI

Length of output: 7410


🏁 Script executed:

# Search for all calls to enqueue() to see how it's being used
rg -n "enqueue\s*\(" -C3

Repository: AOSSIE-Org/Devr.AI

Length of output: 2515


🏁 Script executed:

# Check the discord bot initialization to see how queue_manager is set up
grep -n "queue_manager\|AsyncQueueManager" backend/integrations/discord/bot.py -C5

Repository: AOSSIE-Org/Devr.AI

Length of output: 2013


🏁 Script executed:

# Check the agent_coordinator to see how queue_manager is initialized there
grep -n "queue_manager\|AsyncQueueManager" backend/app/core/orchestration/agent_coordinator.py -C5

Repository: AOSSIE-Org/Devr.AI

Length of output: 1806


🏁 Script executed:

# Check the cogs.py to understand the queue initialization
grep -n "queue\|AsyncQueueManager" backend/integrations/discord/cogs.py -C5

Repository: AOSSIE-Org/Devr.AI

Length of output: 2138


🏁 Script executed:

# Find the main entry point and bot startup logic
find . -name "main.py" -o -name "run.py" -o -name "app.py" | head -5

Repository: AOSSIE-Org/Devr.AI

Length of output: 79


🏁 Script executed:

# Search for where the bot and queue_manager are initialized
rg -n "AsyncQueueManager\(\|DiscordBot\(" -C5 | head -60

Repository: AOSSIE-Org/Devr.AI

Length of output: 44


🏁 Script executed:

# Check if there's a startup sequence or main module
find . -name "*.py" -path "*/backend/*" -type f | grep -E "(main|run|startup|__main__|server)" | head -10

Repository: AOSSIE-Org/Devr.AI

Length of output: 181


🏁 Script executed:

# Check the main.py to see the startup sequence
cat -n ./backend/main.py

Repository: AOSSIE-Org/Devr.AI

Length of output: 6106


Guard enqueue() against disconnected/uninitialized queue manager.

If enqueue() is called before connect()/start() completes or after stop() is invoked, self.channel is either None or closed, causing runtime failures. Add a defensive guard:

    async def enqueue(
        self,
        message: Dict[str, Any],
        priority: QueuePriority = QueuePriority.MEDIUM,
        delay: float = 0,
    ) -> None:
        """Add a message to the single priority queue."""
+        if not self.channel:
+            raise RuntimeError("Queue manager not connected. Call start() before enqueue().")
         if delay > 0:
             await asyncio.sleep(delay)

Note: The stop() method should also reset self.channel = None to ensure the guard catches post-shutdown attempts.

🤖 Prompt for AI Agents
In `@backend/app/core/orchestration/queue_manager.py` around lines 87 - 109, Guard
the enqueue method against an uninitialized or closed channel by checking
self.channel exists and is open before publishing (in the enqueue function) and
raise or log a clear error if not ready; update stop() to explicitly set
self.channel = None (and any related connection state) so post-shutdown calls
hit the guard; reference the enqueue method's use of
self.channel.default_exchange.publish and the stop/connect/start lifecycle
methods to implement these checks and state resets.

Comment on lines +15 to +16
"@mui/icons-material": "^7.3.7",
"@mui/material": "^7.3.7",
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:

MUI Material @mui/material v7.3.7 React 18 compatibility peer dependencies

💡 Result:

For MUI Material @mui/material@7.3.7, the React 18-compatible peer dependency ranges are:

"peerDependencies": {
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
  "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
}

[1]

Important for React 18 (and below): MUI v7 uses react-is@19, so if you’re on React 18 you should pin/override react-is to the same version as your react (e.g., react-is@18.3.1) to avoid runtime issues. [1][2]

Sources: [1] MUI v7.3.7 Installation docs, [2] MUI “Upgrade to v7” migration docs.


Pin react-is to match React version to avoid runtime issues with MUI v7.

MUI v7.3.7 is compatible with React 18.2.0, but v7 uses react-is@19. Add or update resolutions (yarn) or overrides (npm 8.13+) to pin react-is@18.3.1 to match your React version and prevent runtime issues.

🤖 Prompt for AI Agents
In `@landing/package.json` around lines 15 - 16, Update package.json to pin the
react-is package to the React 18-compatible release so MUI v7 doesn't pull
react-is@19; add or update the dependency resolution settings (use "resolutions"
for yarn or "overrides" for npm >=8.13+) to force "react-is": "18.3.1" alongside
your existing dependencies ("@mui/material" and "@mui/icons-material") and run
install to lock the transitive version.

Comment on lines +28 to +74
const QuickLink: React.FC<{ link: { label: string; href: string }; isHomePage: boolean }> = ({ link, isHomePage }) => {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();

// Construct target href (preserve hash). On non-home pages we prefix with '/'
const target = isHomePage ? link.href : `/${link.href}`;

// Navigate so location.hash updates; scrolling is handled by Navbar's useEffect
navigate(target);
};

return (
<MuiLink
href={link.href}
onClick={(e) => handleClick(e)}
className="text-gray-400 hover:text-green-400 text-sm transition-colors duration-300 inline-flex items-center gap-2 group"
sx={{
color: 'rgba(161, 161, 170, 1)',
fontSize: '0.875rem',
textDecoration: 'none',
display: 'inline-flex',
alignItems: 'center',
gap: '8px',
position: 'relative',
transition: 'color 0.3s ease',
'&:hover': {
color: 'rgba(34, 197, 94, 1)',
},
'&::before': {
content: '""',
width: 0,
height: '2px',
background: 'linear-gradient(to right, #4ade80, #22d3ee)',
transition: 'width 0.3s ease',
position: 'absolute',
left: 0,
bottom: '-2px',
},
'&:hover::before': {
width: '16px',
},
}}
>
{link.label}
</MuiLink>
);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Move QuickLink outside the Footer component to prevent unnecessary re-renders.

QuickLink is defined inside Footer, causing it to be recreated on every render. This breaks React's reconciliation and can cause performance issues. Move it outside the component, passing navigate and isHomePage as props or via context.

♻️ Suggested refactor
+interface QuickLinkProps {
+    link: { label: string; href: string };
+    isHomePage: boolean;
+    navigate: ReturnType<typeof useNavigate>;
+}
+
+const QuickLink: React.FC<QuickLinkProps> = ({ link, isHomePage, navigate }) => {
+    const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
+        e.preventDefault();
+        const target = isHomePage ? link.href : `/${link.href}`;
+        navigate(target);
+    };
+
+    return (
+        <MuiLink
+            href={link.href}
+            onClick={handleClick}
+            // ... rest of the component
+        >
+            {link.label}
+        </MuiLink>
+    );
+};

 const Footer: React.FC = () => {
     const currentYear = new Date().getFullYear();
     const location = useLocation();
     const isHomePage = location.pathname === '/';
     const navigate = useNavigate();
-
-    // QuickLink component to handle hash navigation/smooth scroll via router
-    const QuickLink: React.FC<{ link: { label: string; href: string }; isHomePage: boolean }> = ({ link, isHomePage }) => {
-        // ... component definition
-    };
🤖 Prompt for AI Agents
In `@landing/src/components/layout/Footer.tsx` around lines 28 - 74, QuickLink is
declared inside Footer causing re-creation on each render; move the QuickLink
component definition out of Footer (make it a top-level component) and update
its signature to accept props for navigate and isHomePage (or obtain navigate
via context) so Footer passes navigate and isHomePage into QuickLink; ensure the
prop type remains React.FC<{ link: { label: string; href: string }; isHomePage:
boolean; navigate: (to: string) => void }> (or adjust if using context) and
update Footer usage to pass the values accordingly.

Comment on lines +53 to +60
const handleSmoothScroll = (e:React.MouseEvent<HTMLAnchorElement>, href: string) => {
e.preventDefault();
// Do not prevent default navigation; close mobile menu then navigate so location.hash updates
setIsOpen(false);

// Navigate to the link (includes hash when present). The useEffect above will handle scrolling.
navigate(href);
};
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

Misleading comment contradicts the code.

Line 55's comment says "Do not prevent default navigation" but e.preventDefault() is called on line 54. The comment should be updated or removed to accurately reflect the behavior.

📝 Suggested fix
     const handleSmoothScroll = (e:React.MouseEvent<HTMLAnchorElement>, href: string) => {
         e.preventDefault();
-        // Do not prevent default navigation; close mobile menu then navigate so location.hash updates
+        // Close mobile menu then navigate so location.hash updates; scrolling handled by useEffect
         setIsOpen(false);
 
-        // Navigate to the link (includes hash when present). The useEffect above will handle scrolling.
         navigate(href);
     };
📝 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 handleSmoothScroll = (e:React.MouseEvent<HTMLAnchorElement>, href: string) => {
e.preventDefault();
// Do not prevent default navigation; close mobile menu then navigate so location.hash updates
setIsOpen(false);
// Navigate to the link (includes hash when present). The useEffect above will handle scrolling.
navigate(href);
};
const handleSmoothScroll = (e:React.MouseEvent<HTMLAnchorElement>, href: string) => {
e.preventDefault();
// Close mobile menu then navigate so location.hash updates; scrolling handled by useEffect
setIsOpen(false);
navigate(href);
};
🤖 Prompt for AI Agents
In `@landing/src/components/layout/Navbar.tsx` around lines 53 - 60, Update the
misleading comment inside handleSmoothScroll to match the actual behavior: since
e.preventDefault() is called, remove or rephrase the line that says "Do not
prevent default navigation" so it accurately states that default navigation is
prevented, the mobile menu is closed via setIsOpen(false), and navigation is
performed programmatically with navigate(href) (the scrolling is handled
elsewhere by the useEffect). Ensure the comment references handleSmoothScroll,
e.preventDefault(), setIsOpen, and navigate for clarity.

Comment on lines +142 to +153
.btn-primary::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, var(--color-primary-400) 0%, var(--color-primary-500) 100%);
opacity: 0;
transition: opacity 0.4s ease;
z-index: -1;
}
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

🧩 Analysis chain

🏁 Script executed:

# First, let's see the full button styling context around lines 130-160
sed -n '130,165p' landing/src/index.css

Repository: AOSSIE-Org/Devr.AI

Length of output: 1064


🏁 Script executed:

# Check if there's a Button.tsx component
find landing -name "Button.tsx" -o -name "Button.ts" -o -name "Button.jsx" -o -name "Button.js" | head -20

Repository: AOSSIE-Org/Devr.AI

Length of output: 98


🏁 Script executed:

# Search for z-index usage in the CSS file to understand the full layering strategy
rg -n "z-index" landing/src/index.css | head -20

Repository: AOSSIE-Org/Devr.AI

Length of output: 173


🏁 Script executed:

# Check for button-related classes and their styling
rg -n "\.btn-" landing/src/index.css | head -30

Repository: AOSSIE-Org/Devr.AI

Length of output: 593


🏁 Script executed:

# Let's see the hover states to understand the intended animation behavior
sed -n '169,195p' landing/src/index.css

Repository: AOSSIE-Org/Devr.AI

Length of output: 602


🏁 Script executed:

# Also check the full context of btn-secondary to see if same pattern is used
sed -n '196,260p' landing/src/index.css

Repository: AOSSIE-Org/Devr.AI

Length of output: 1612


🏁 Script executed:

# Check if Button.tsx uses inline styles that might override or complement these styles
cat -n landing/src/components/ui/Button.tsx | head -80

Repository: AOSSIE-Org/Devr.AI

Length of output: 3100


🏁 Script executed:

# Check if the landing page uses the btn-primary class from index.css or relies on Button.tsx
rg -n "btn-primary\|btn-secondary" landing/src --include="*.html" --include="*.tsx" --include="*.jsx" | head -20

Repository: AOSSIE-Org/Devr.AI

Length of output: 503


🏁 Script executed:

# Verify if there are any visual effects or animations that might work around this z-index issue
sed -n '140,260p' landing/src/index.css | grep -A 2 -B 2 "opacity:"

Repository: AOSSIE-Org/Devr.AI

Length of output: 508


🏁 Script executed:

# Check where btn-primary/btn-secondary classes are actually used
rg "btn-primary|btn-secondary" landing/src -t css -t html -t tsx -t jsx 2>/dev/null | head -30

Repository: AOSSIE-Org/Devr.AI

Length of output: 44


🏁 Script executed:

# Simpler search - just look for button usage patterns in landing pages
fd "\.tsx$|\.jsx$|\.html$" landing/src | xargs grep -l "btn-primary\|btn-secondary" 2>/dev/null | head -10

Repository: AOSSIE-Org/Devr.AI

Length of output: 102


🏁 Script executed:

# Check Hero.tsx to see how btn-primary and btn-secondary are used
cat -n landing/src/components/sections/Hero.tsx

Repository: AOSSIE-Org/Devr.AI

Length of output: 20022


🏁 Script executed:

# Also check if there are any developer notes or comments about the z-index layering
rg -n "z-index|layering|stacking" landing/src/index.css -B 2 -A 2

Repository: AOSSIE-Org/Devr.AI

Length of output: 590


z-index: -1 on ::before creates a stacking bug, but inline styles currently bypass it.

The .btn-primary::before and .btn-secondary::before pseudo-elements with z-index: -1 are placed behind the parent button's background gradient, making the opacity transition ineffective. However, the Hero component uses inline sx overrides that replace the CSS hover animation with backgroundPosition changes, so the bug doesn't manifest in practice. This should still be fixed for consistency: change z-index: -1 to z-index: 1 for ::before, keep z-index: 0 for ::after, and z-index: 10 for content—or remove the unused CSS animation rules if inline styles are the intended approach.

🤖 Prompt for AI Agents
In `@landing/src/index.css` around lines 142 - 153, The pseudo-element stacking
for buttons is wrong: update .btn-primary::before and .btn-secondary::before to
use z-index: 1 (instead of -1), ensure any corresponding ::after pseudo-element
keeps z-index: 0, and ensure the button inner content (e.g., the element
targeted by .btn-primary .content or the main button selector) has z-index: 10
so the gradient sits behind content but above the button background;
alternatively, if the Hero component intentionally uses inline sx overrides for
backgroundPosition and you want to remove the unused animation, delete the
::before/::after animation/transition rules for .btn-primary/.btn-secondary and
rely on the inline styles used in the Hero component.

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.

ENHANCEMENT:Queue Worker Inefficient Polling

1 participant