Skip to content

[FEAT] Industries Carousel (TX-2341)#4

Draft
claudiaaziz wants to merge 11 commits intomainfrom
feature/tx-2341-industries-carousel
Draft

[FEAT] Industries Carousel (TX-2341)#4
claudiaaziz wants to merge 11 commits intomainfrom
feature/tx-2341-industries-carousel

Conversation

@claudiaaziz
Copy link
Contributor

No description provided.

@claudiaaziz claudiaaziz self-assigned this Jan 16, 2026
@claudiaaziz claudiaaziz added the enhancement New feature or request label Jan 16, 2026
@changeset-bot
Copy link

changeset-bot bot commented Jan 16, 2026

⚠️ No Changeset found

Latest commit: a9f9ea5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Contributor

vercel bot commented Jan 16, 2026

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

Project Deployment Review Updated (UTC)
tillisoftware Error Error Jan 22, 2026 3:57pm

Request Review

@claude
Copy link

claude bot commented Jan 16, 2026

PR Review: Industries Carousel (TX-2341)

This PR refactors the solutions carousel to use Embla Carousel library.

Positive Aspects

  • Embla Carousel is a solid, lightweight library with good React integration
  • Properly added embla-carousel-class-names plugin for opacity transitions
  • Fixed Next.js remotePatterns configuration from new URL() to proper object structure
  • Good component modularization with folder structure

Critical Issues

1. Massive Base64 Data File (Critical)
The data.ts file contains over 30KB of base64-encoded images. This significantly increases bundle size, hurts performance, bloats version control, and provides no browser caching benefits. Store images as separate files in /public/assets/ like the business-carousel.tsx pattern.

2. Hardcoded Placeholder Images
Using Lorem Picsum placeholder images. The PR is titled Industries Carousel but displays random images. Replace with actual industry-specific images.

3. Placeholder Alt Text
Non-descriptive alt text fails WCAG accessibility guidelines. Use descriptive alt text for each industry image.

Code Quality Issues

4. Unused emblaApi Instance
emblaApi is declared but never used, triggering linting warnings. Either use it for controls or rename to _emblaApi.

5. Commented Out Code
Multiple instances of commented code throughout the PR. Remove or document why preserved.

6. Inconsistent Patterns
business-carousel.tsx uses SVG files, but solutions carousel uses external URLs. Establish consistent pattern.

Security

7. External Image Domain
Adding picsum.photos to remotePatterns is fine for dev but should not reach production. Remove once real assets are in place.

Testing

8. No Test Coverage
No test files found. Add basic tests for component rendering, slide navigation, autoplay, and accessibility.

Action Items

Must Fix Before Merge:

  1. Replace base64 images in data.ts with proper asset files
  2. Replace Lorem Picsum URLs with actual industry images
  3. Add descriptive alt text for all images
  4. Remove picsum.photos from remotePatterns

Should Fix:
5. Remove commented-out code
6. Address unused emblaApi variable
7. Add basic component tests
8. Improve TypeScript types

Overall Assessment

Code Quality: Needs Improvement
Security: Acceptable (with production caveat)
Performance: Blocked by base64 images
Accessibility: Needs alt text improvements
Test Coverage: None

Recommendation: Request Changes - Solid foundation with Embla integration, but base64 image data and placeholder content need resolution before merging. Implementation appears incomplete for the stated feature.

Review generated by Claude Code

@claude
Copy link

claude bot commented Jan 19, 2026

PR Review: Industries Carousel Refactor (TX-2341)

Overview

This PR successfully refactors the solutions carousel from a custom implementation to use Embla Carousel library. The refactor significantly reduces code complexity (234 deletions vs 159 additions) while improving maintainability.


✅ Strengths

  1. Code Quality & Maintainability

    • Much simpler implementation: Reduced from 232 lines of custom animation logic to 42 lines using a well-maintained library
    • Better separation of concerns: Data extracted to data.ts, component logic in index.tsx, styles in embla.css
    • Cleaner architecture: No more manual state management, interval timers, or complex transform calculations
  2. Improved User Experience

    • Embla provides better touch/swipe support out of the box
    • Smoother animations with hardware acceleration
    • More accessible carousel implementation

🔍 Issues & Concerns

1. Layout Change May Break Design (Medium Priority)

Location: src/app/home/page.tsx:381

- <section className="page-width my-32">
+ <section className="box-border ml-20 my-32">

Issue: Changed from page-width to ml-20 (margin-left: 5rem). This:

  • Removes the right-side constraint that page-width likely provided
  • May cause the carousel to overflow on smaller screens
  • Inconsistent with other sections that use page-width

Recommendation: Verify this change is intentional. If the carousel needs to extend beyond the page width, consider using page-width with an inner container that overflows, or use responsive classes like ml-4 md:ml-20.


2. Missing Description Display (High Priority)

Location: src/app/home/solutions-carousel/index.tsx:19-40

Issue: The original carousel displayed industry descriptions and had interactive buttons. The new implementation only shows the image and name. The descriptions from data.ts are never used.

Original behavior:

<p className="mb-16 max-w-md">{industries[activeIndex].description}</p>

Current behavior: Descriptions are imported but unused.

Recommendation: Either:

  • Add description display back (likely outside the carousel as a synced text block)
  • Remove unused descriptions from data.ts
  • Document that this is intentional UI simplification

3. Image Sizing Mismatch

Location: src/app/home/solutions-carousel/index.tsx:28-34

<Image
  alt={industry.name}
  className="embla__slide__img"
  height={600}
  width={600}
  src={industry.image}
/>

Issues:

  • Next.js Image optimization: Width/height props are 600x600, but actual images are 600x350 (per data.ts URLs)
  • Aspect ratio mismatch: This may cause distortion or layout shifts
  • CSS override: The CSS sets height: var(--slide-height) (19rem ≈ 304px) and width: 100%, which overrides the Image props

Recommendation:

<Image
  alt={industry.name}
  className="embla__slide__img"
  height={350}
  width={600}
  src={industry.image}
/>

4. TODO Comment in Production Code (Low Priority)

Location: src/app/home/solutions-carousel/data.ts:28

// TODO: delete above and uncomment this

Issue: TODO comment suggests temporary implementation with placeholder images.

Recommendation: Either:

  • Remove the TODO and commented code if using Figma assets is the plan
  • Create a proper ticket/issue to track the image swap
  • Update the TODO with context (e.g., "TODO: Swap to Figma assets after design approval")

5. CSS File Import Location

Location: src/app/page.tsx:1

import "../css/embla.css";

Issue: Global CSS imported in the root page file, but the carousel is only used in /home.

Recommendation: Import embla.css in src/app/home/page.tsx instead, or in the carousel component itself if you have CSS module support configured.


6. CSS Variable Not Defined

Location: src/css/embla.css:28

box-shadow: inset 0 0 0 0.2rem var(--detail-medium-contrast);

Issue: --detail-medium-contrast is not defined in the provided CSS file.

Recommendation: Verify this CSS variable exists in your global styles or Tailwind config. If not, it will fall back to an invalid value.


7. Hardcoded Image Dimensions

Location: src/css/embla.css:2

--slide-height: 19rem;

Issue: Hardcoded heights can cause issues:

  • May not match actual image aspect ratios
  • Not responsive across different screen sizes

Recommendation: Consider making this responsive or using aspect-ratio CSS property instead.


8. Next.js Image Configuration

Location: next.config.ts:10-24

Issue: Added picsum.photos to remote patterns, but:

  • This is a placeholder image service (should only be used for dev/testing)
  • The old pattern used new URL("https://placecats.com/**") which is non-standard

Recommendation:

remotePatterns: [
  {
    protocol: "https",
    hostname: "www.figma.com",
    pathname: "/api/mcp/asset/**",
  },
]

Also convert the placecats pattern to the proper object format.


🧪 Testing Concerns

No test coverage observed for either the old or new carousel implementation.

Recommendations:

  1. Add visual regression tests (Chromatic, Percy, or Playwright screenshots)
  2. Add unit tests for:
    • Data structure validation
    • Component rendering with different data
  3. Add E2E tests for:
    • Carousel autoplay
    • Touch/swipe interactions
    • Keyboard navigation (accessibility)

🔒 Security Assessment

✅ No security concerns identified:

  • No XSS vectors (using Next.js Image component)
  • No unsafe dynamic content rendering
  • External images properly configured in Next.js config

🎯 Performance Considerations

Improvements:

  • ✅ Using Next.js Image component (optimization, lazy loading, proper sizing)
  • ✅ Embla is lightweight (~2-3kb per plugin)
  • ✅ Hardware-accelerated transforms

Potential Concerns:

  • ⚠️ Loading 4 images on initial render (old version also had this issue)
  • ⚠️ No priority loading for the first/active slide

Recommendation:

<Image
  alt={industry.name}
  className="embla__slide__img"
  height={350}
  width={600}
  src={industry.image}
  priority={index === 0} // Prioritize first image
/>

📋 Summary & Recommendations

Priority Fixes Before Merge:

  1. Restore description display or remove unused data
  2. Fix image dimensions (600x350 not 600x600)
  3. ⚠️ Review layout change (ml-20 vs page-width)
  4. ⚠️ Move CSS import to home page or component

Post-Merge Improvements:

  • Add test coverage
  • Make carousel responsive
  • Verify CSS variables are defined
  • Update image URLs to production assets
  • Add priority prop to first image

🎉 Conclusion

This is a solid refactor that improves code quality and maintainability. The main concerns are around missing UI functionality (descriptions) and some sizing mismatches. With the high-priority items addressed, this will be ready to merge.

Great job simplifying the implementation! 🚀

@claude
Copy link

claude bot commented Jan 20, 2026

Code Review - PR #4: Industries Carousel (TX-2341)

This PR refactors the solutions carousel to use Embla Carousel library. Good work on the refactor, but several issues need to be addressed.

Critical Issues

1. Duplicate Data (HIGH) - data.ts contains the same 4 industries repeated twice (8 total). Remove duplicates or explain why they're needed.

2. Unused Component (MEDIUM) - TextContentSection.tsx is never imported/used. It also has a bug: line 22 uses invalid CSS class 'bg-linear-to-r' (should be 'bg-gradient-to-r'). Either integrate it or remove it.

3. React Keys Issue (MEDIUM) - index.tsx line 26 maps industries using industry.name as key. With duplicate data, this causes key collisions. Use unique IDs or add index prefix.

Code Quality

4. Styling Change - page.tsx:381 changed from 'page-width' to 'ml-20'. This breaks responsive design. Explain why or revert.

5. Accessibility - Missing ARIA labels, keyboard navigation, and screen reader support. Add role='region', aria-label, and aria-live attributes.

6. Autoplay Config - No configuration for delay, stopOnInteraction, or stopOnMouseEnter (accessibility best practice).

Performance

7. Image Optimization - Hardcoded 600x600 doesn't match display size (19rem). Add sizes prop and correct dimensions.

8. CSS Import - embla.css imported globally in page.tsx. Move to component file for better code splitting.

Security

9. Image Domains - picsum.photos is temp. Commented code shows production uses figma.com API which requires auth tokens and may break. Plan migration to CDN/local storage.

Testing

10. No Tests - Add tests for carousel initialization, autoplay, unidirectional scroll, and accessibility.

Positive Notes

  • Good separation of concerns
  • Modern Embla Carousel choice
  • Proper event cleanup
  • CSS custom properties
  • Next.js Image optimization

Before Merging

  1. Remove duplicate industries
  2. Fix/remove TextContentSection.tsx
  3. Fix React keys
  4. Explain ml-20 change
  5. Move CSS import
  6. Add accessibility
  7. Configure Autoplay
  8. Plan production images

Overall solid refactor but needs cleanup before merge.

@claude
Copy link

claude bot commented Jan 20, 2026

Pull Request Review: Industries Carousel (TX-2341)

I've reviewed this PR and have the following feedback organized by category:


🐛 Critical Issues

1. Duplicate Data in Industries Array (data.ts:1-50)

The industries array contains duplicate entries - each industry appears twice. This is likely unintentional and will cause:

  • Duplicate keys in React rendering (though React keys use industry.name)
  • Confusing carousel behavior showing the same items multiple times
  • Misleading user experience

Recommendation: Remove the duplicates unless this is intentional for testing purposes. If duplicates are needed for infinite loop behavior, document why.

2. Non-unique React Keys (index.tsx:26-29)

Using industry.name as the key is problematic when there are duplicates in the array:

key={industry.name}  // ⚠️ Not unique with current data

Recommendation: Use a unique identifier. Options:

key={`${industry.name}-${index}`}
// or generate unique IDs in the data file

3. Unused Component (TextContentSection.tsx)

The TextContentSection component is created but never imported or used. This creates dead code and confusion.

Recommendation: Either integrate this component into the carousel or remove it. If it's for future use, add a comment explaining the plan.


🔒 Security Concerns

1. External Image Sources

Using picsum.photos for production is a security and reliability risk:

  • No control over content (images could change)
  • Privacy concerns (external tracking)
  • Performance/availability dependency on third-party service

Recommendation: The TODO comment suggests this is temporary, but ensure the Figma assets or self-hosted images are used before merging to production.


Performance Considerations

1. Missing Image Optimization

The Next.js Image component is used correctly, but missing some optimization props:

<Image
  alt={industry.name}
  className="embla__slide__img"
  height={600}
  width={600}
  src={industry.image}
  // Missing: priority, loading, sizes, quality
/>

Recommendation: Add appropriate image optimization props:

<Image
  alt={industry.name}
  className="embla__slide__img"
  height={600}
  width={600}
  src={industry.image}
  sizes="(max-width: 768px) 100vw, 30vw"
  loading="lazy"
  quality={85}
/>

2. Event Listener Memory Management

The useUnidirectionalEmbla hook properly cleans up event listeners in the useEffect return, which is good. However, consider using passive: true for better scroll performance where preventDefault isn't needed:

  • Keep passive: false only for pointermove where you call preventDefault()
  • Use passive: true for pointerdown, pointerup, pointercancel

🎨 Code Quality & Best Practices

1. Empty CSS Rule (embla.css:12-13)

.embla__viewport {
}

Empty CSS rules should be removed or commented with a TODO if planned for future use.

2. Typo in Tailwind Class (TextContentSection.tsx:22)

className="whitespace-nowrap bg-linear-to-r from-blue-400 to-blue-600..."

Should be bg-gradient-to-r not bg-linear-to-r. This will cause the gradient not to render.

3. Hardcoded Magic Numbers (embla.css:28, useUnidirectionalEmbla.ts)

transform: translateY(-100px) !important;

Consider using CSS variables for maintainability:

--slide-active-offset: -100px;
transform: translateY(var(--slide-active-offset)) !important;

4. Missing Accessibility Features

  • No ARIA labels for carousel navigation
  • No keyboard navigation support (arrow keys to navigate slides)
  • No aria-live region to announce slide changes to screen readers

Recommendation:

<section className="embla overflow-hidden" aria-label="Industry solutions carousel">
  <div className="embla__viewport" ref={emblaRef} role="region" aria-roledescription="carousel">
    {/* ... */}
  </div>
</section>

5. Inconsistent Styling Approach (page.tsx:381)

className="box-border ml-20 my-32"

The change from page-width to box-border ml-20 breaks consistency. The ml-20 (5rem/80px) seems arbitrary and won't be responsive.

Recommendation: Maintain consistent spacing utilities or document why this section needs different treatment.


🧪 Test Coverage

Missing Tests

No test files were found for the carousel components. Consider adding tests for:

  • Carousel rendering with different data sets
  • Autoplay functionality
  • Unidirectional scrolling behavior (blocking backward scrolls)
  • Keyboard navigation
  • Accessibility features

Recommendation: Add basic component tests:

// solutions-carousel/index.test.tsx
describe('SolutionsCarousel', () => {
  it('renders all industries', () => {});
  it('prevents backward scrolling', () => {});
  it('auto-advances slides', () => {});
});

Positive Notes

  1. Good refactoring - Breaking the monolithic carousel into modular files improves maintainability
  2. Proper cleanup - Event listeners are correctly removed in useEffect cleanup
  3. Type safety - Good use of TypeScript types, especially in useUnidirectionalEmbla
  4. Next.js Image - Correctly using Next.js Image component for optimization
  5. Embla integration - Clean integration with Embla carousel library and plugins

📋 Action Items Before Merge

Must Fix:

  1. Remove duplicate entries in industries array or document why they're needed
  2. Fix React key uniqueness issue
  3. Fix typo: bg-linear-to-rbg-gradient-to-r
  4. Remove or integrate unused TextContentSection component
  5. Remove empty CSS rule

Should Fix:
6. Add accessibility features (ARIA labels, keyboard navigation)
7. Review the ml-20 spacing change for consistency
8. Add image optimization props
9. Plan to replace picsum.photos with real assets before production

Nice to Have:
10. Add test coverage
11. Optimize event listener passive flags
12. Use CSS variables for magic numbers


Let me know if you'd like me to elaborate on any of these points or help implement any fixes!

@claude
Copy link

claude bot commented Jan 20, 2026

Pull Request Review: Industries Carousel (TX-2341)

Summary

This PR refactors the solutions carousel from a custom implementation to use Embla Carousel with a unidirectional scrolling behavior. Overall, the refactoring improves code organization and leverages a well-maintained carousel library. However, there are several issues that should be addressed before merging.


🔴 Critical Issues

1. Duplicate Data in Array (src/app/home/solutions-carousel/data.ts:1-50)

The industries array contains duplicate entries - all 4 industries are repeated twice (lines 1-25 and 26-49). This appears to be unintentional and will cause:

  • Duplicate keys in React rendering (industry.name is used as key)
  • Confusing UX with repeated content
  • React Warning: "Each child in a list should have a unique key prop"

Recommendation: Remove the duplicate entries or add a unique identifier if duplicates are intentional.

2. Missing Unique Keys (src/app/home/solutions-carousel/index.tsx:27-30)

Using industry.name as the key is problematic since there are duplicates in the data array.

key={industry.name}  // ❌ Not unique with current data

Recommendation: Use index or a unique ID:

key={`${industry.name}-${index}`}

3. Unused Component (src/app/home/solutions-carousel/TextContentSection.tsx)

The TextContentSection component is created but never imported or used anywhere in the codebase. This is dead code.

Recommendation: Either integrate it into the carousel or remove it to keep the codebase clean.

4. Invalid Tailwind Class (src/app/home/solutions-carousel/TextContentSection.tsx:22)

className="whitespace-nowrap bg-linear-to-r from-blue-400 to-blue-600..."

bg-linear-to-r is not a valid Tailwind class. It should be bg-gradient-to-r.


⚠️ High Priority Issues

5. Empty CSS Rule (src/css/embla.css:13-14)

.embla__viewport {
}

Empty CSS rules should be removed.

6. Excessive !important Usage (src/css/embla.css:29)

transform: translateY(-60px) !important;

Using !important suggests CSS specificity issues. This makes the code harder to maintain.

Recommendation: Restructure CSS to avoid needing !important.

7. Acknowledged Bug in Comment (src/app/home/solutions-carousel/index.tsx:13)

loop: true, // for some reason this is buggy, but we need this

This comment indicates known buggy behavior. This is a red flag for production code.

Recommendation: Either:

  • Investigate and fix the bug
  • Document the specific issue and workaround
  • Consider alternative approaches if the bug impacts UX

8. Next.js Image Optimization Incompatibility

The carousel uses remote images from picsum.photos (which are temporary placeholders), and the Next.js Image component requires proper configuration. While next.config.ts was updated to allow picsum.photos, these are placeholder images that should be replaced before production.

Recommendation: Update the TODO comment with a timeline or create a follow-up ticket.


🟡 Medium Priority Issues

9. Missing Event Listener Cleanup Dependency

In useUnidirectionalEmbla.ts:54, the useEffect dependency array only includes emblaApi, but the effect uses refs that could potentially cause stale closures.

Recommendation: Review if additional dependencies are needed or add ESLint disable comment with explanation if intentional.

10. Accessibility Issues

a) Missing Image Priority (index.tsx:32-38)
Images in the carousel should consider using priority prop for the first visible image to improve LCP (Largest Contentful Paint).

b) Keyboard Navigation
The unidirectional hook blocks backward scrolling with pointer events, but there's no handling for keyboard navigation (arrow keys). Users relying on keyboard navigation may have a poor experience.

Recommendation: Add keyboard event handlers or document that keyboard navigation is intentionally one-directional.

11. Layout Shift Risk (src/app/home/page.tsx:381)

<section className="box-border ml-20 my-32">

Changed from page-width to box-border ml-20. This hardcoded margin could cause layout inconsistencies and is not responsive.

Recommendation: Use the existing page-width utility or create a proper responsive class.


💡 Code Quality & Best Practices

12. Magic Numbers

Several hardcoded values without explanation:

  • translateY(-60px) in CSS (line 29)
  • opacity: 0.16 (line 33)
  • --slide-size: 30% (line 6)
  • min-height: 40rem (line 3)

Recommendation: Extract to CSS variables with descriptive names or add comments explaining the values.

13. Type Safety

The activeIndustry prop in TextContentSection uses an inline type:

activeIndustry: { name: string; description: string };

Recommendation: Create a shared type/interface for the industry object to ensure consistency across components.

14. Missing Error Boundaries

No error boundaries around the carousel. If the Embla library fails to initialize, the entire component tree could crash.

Recommendation: Add error boundary or defensive checks.


🔒 Security Concerns

15. External Image Sources

Using external image sources (picsum.photos, Figma MCP assets) without Content Security Policy considerations. While Next.js Image component provides some protection, consider:

  • CSP headers for image sources
  • Fallback images for when external sources fail
  • Moving images to your own CDN for production

✅ Performance Considerations

16. Pointer Event Listeners Set to Non-Passive

viewport.addEventListener("pointerdown", onPointerDown, { passive: false });
viewport.addEventListener("pointermove", onPointerMove, { passive: false });

Setting passive: false can impact scroll performance since it prevents browser optimizations. However, this is necessary here since preventDefault() is called.

Status: Acceptable given the functionality requirements, but be aware of potential performance impact on mobile devices.

17. Bundle Size

Added dependencies:

  • embla-carousel-autoplay
  • embla-carousel-class-names

Status: These are legitimate dependencies, but monitor bundle size impact.


🧪 Test Coverage

No tests detected for the new carousel components. Given the custom unidirectional scrolling logic, this should have:

  • Unit tests for the useUnidirectionalEmbla hook
  • Integration tests for the carousel behavior
  • Visual regression tests for the carousel states

Recommendation: Add test coverage before merging.


📝 Summary of Required Changes Before Merge

  1. ✅ Remove duplicate entries in data.ts or fix unique keys
  2. ✅ Fix invalid Tailwind class bg-linear-to-rbg-gradient-to-r
  3. ✅ Remove unused TextContentSection component or integrate it
  4. ✅ Address or document the "buggy" loop behavior
  5. ✅ Add unique keys for carousel items
  6. ✅ Remove empty CSS rule
  7. ✅ Add basic test coverage for the hook
  8. ⚠️ Consider keyboard accessibility
  9. ⚠️ Review layout change from page-width to hardcoded margin

✨ Positive Notes

  • Good separation of concerns: Breaking the carousel into separate files (data, hook, component) improves maintainability
  • Custom hook is well-structured: The useUnidirectionalEmbla hook is focused and reusable
  • Proper cleanup: Event listeners are properly cleaned up in the useEffect
  • Type safety: Good use of TypeScript types throughout
  • Progressive enhancement: Falls back gracefully if emblaApi is undefined

Great work on the refactoring! Please address the critical issues before merging.

@claude
Copy link

claude bot commented Jan 21, 2026

Pull Request Review: Industries Carousel (TX-2341)

Summary

This PR refactors the Solutions Carousel component by splitting a monolithic file into a modular structure with separate concerns. The carousel now uses Embla Carousel with a custom unidirectional scrolling behavior.


Code Quality & Best Practices

✅ Strengths

  • Good separation of concerns: Breaking the carousel into index.tsx, TextContentSection.tsx, data.ts, and useUnidirectionalEmbla.ts improves maintainability
  • Proper use of React hooks: Custom hook useUnidirectionalEmbla is well-structured with proper cleanup
  • Type safety: Good TypeScript usage with proper typing for props and Embla API

⚠️ Issues Found

1. Non-functional Button Click Handler (src/app/home/solutions-carousel/index.tsx:27-28)

<TextContentSection
  activeIndustry={industries[0]}
  handleIndustryClick={() => {}}  // ❌ Empty function
/>

The handleIndustryClick callback is empty and activeIndustry is hardcoded to industries[0]. This means:

  • The button in TextContentSection does nothing when clicked
  • The text content never updates when slides change
  • The function signature expects (index: number) => void but receives () => {}, which is a type mismatch

Recommendation: Either connect this to the Embla API to update slides, or remove the button/callback if it's not meant to be interactive yet.

2. Invalid CSS Class (src/app/home/solutions-carousel/TextContentSection.tsx:19)

className="flex items-center gap-6 p-0! overflow-visible h-full transition-all duration-300 bg-transparent hover:bg-transparent font-normal"

The class p-0! is invalid Tailwind syntax. It should be !p-0 (exclamation mark comes first in Tailwind v3+).

3. Invalid Tailwind Class (src/app/home/solutions-carousel/TextContentSection.tsx:22)

className="whitespace-nowrap bg-linear-to-r from-blue-400 to-blue-600 bg-clip-text font-header text-5xl text-transparent leading-tight"

bg-linear-to-r should be bg-gradient-to-r.

4. Duplicate Data (src/app/home/solutions-carousel/data.ts)

The industries array duplicates all 4 items twice (lines 1-50), resulting in 8 identical entries. While this might be intentional for infinite scroll, it:

  • Creates confusion with duplicate keys in React (line 38 uses industry.name as key)
  • Could cause issues if items need unique identifiers
  • Makes the array harder to maintain

Recommendation: If duplicates are needed for Embla's loop functionality, generate them programmatically or add unique IDs.

5. Empty CSS Rule Block (src/css/embla.css:13-14)

.embla__viewport {
}

This empty rule should be removed.

6. Unclear Comment (src/app/home/solutions-carousel/index.tsx:14)

loop: true, // for some reason this is buggy, but we need this

This comment raises concerns. If there's a known bug with loop: true, it should be documented more thoroughly or addressed. What's the bug? Is there a workaround? This needs clarification.

7. Incorrect Type Signature (src/app/home/solutions-carousel/TextContentSection.tsx:20)

onClick={() => handleIndustryClick(activeIndustry)}

handleIndustryClick expects (index: number) => void but receives activeIndustry object. This is a type error.


Potential Bugs

🐛 Critical Issues

  1. React Key Warning: Using industry.name as the key (line 38 in index.tsx) will cause warnings since there are duplicate names in the array. Use unique identifiers or indices combined with some unique value.

  2. Non-functional Interaction: The entire text content section appears non-functional due to the empty callback and hardcoded first industry.

  3. Missing Event Listener Cleanup Dependencies: In useUnidirectionalEmbla.ts:54, the cleanup function doesn't include all event listeners that should be removed. While the current implementation looks correct, ensure all listeners added are also removed.

⚠️ Moderate Issues

  1. CSS !important Usage (src/css/embla.css:29):
transform: translateY(-60px) !important;

Using !important suggests a specificity issue. Consider restructuring CSS to avoid this.

  1. Magic Numbers: Values like -60px (line 29 embla.css), 0.16 opacity (line 33 embla.css) should be constants or CSS variables for maintainability.

Performance Considerations

✅ Good Practices

  • Proper use of useRef for storing mutable values without causing re-renders
  • Event listener cleanup in useEffect
  • Using Next.js Image component for optimized images

⚠️ Concerns

  1. Unnecessary Re-renders: activeIndustry={industries[0]} means this value never changes, but React still passes it down as a prop on every render. Consider memoization if this component becomes more complex.

  2. Event Listener Performance: The pointermove event fires very frequently. The current implementation is good, but ensure testing on lower-end devices.

  3. Image Loading: Using picsum.photos with query parameters (?v=1, ?v=2) might not leverage caching effectively since Next.js Image component may treat each as a different URL.


Security Concerns

⚠️ Issues

  1. External Image Sources:

    • Currently using picsum.photos (placeholder service)
    • The commented code references figma.com/api/mcp/asset/ URLs

    Both external domains are now whitelisted in next.config.ts, but:

    • Figma API URLs may have authentication requirements or rate limits
    • Ensure these URLs are stable and won't break in production
    • Consider hosting images on your own CDN for better control
  2. User Input Validation: The handleIndustryClick function (when implemented) should validate the index parameter to prevent out-of-bounds access.

  3. Passive Event Listeners: The pointer event listeners use { passive: false } (lines 44-45 in useUnidirectionalEmbla.ts), which is necessary for preventDefault(), but this can impact scroll performance. This is acceptable given the UX requirement, but document why it's needed.


Test Coverage

❌ No Tests Visible

The PR doesn't include any test files. Consider adding tests for:

  1. useUnidirectionalEmbla Hook:

    • Test that backward scrolling is blocked
    • Test that forward scrolling works
    • Test event listener cleanup
    • Test behavior when emblaApi is undefined
  2. TextContentSection Component:

    • Test button click behavior
    • Test rendering with different industries
    • Test accessibility (button should have proper ARIA labels)
  3. SolutionsCarousel Component:

    • Test carousel initialization
    • Test autoplay functionality
    • Test with different numbers of slides

Additional Recommendations

  1. Accessibility:

    • The Button in TextContentSection should have proper aria-label
    • Carousel should have proper ARIA roles and labels
    • Consider keyboard navigation support
  2. Responsive Design: The CSS uses fixed values (e.g., --slide-size: 30%, min-height: 40rem). Ensure this works well on mobile devices.

  3. Layout Shift (src/app/home/page.tsx:381):

className="box-border ml-20 my-32"

Changing from page-width to ml-20 seems like a workaround. This should be reviewed to ensure it's intentional and doesn't cause layout issues.

  1. Data Management: Consider adding TypeScript interfaces for the industry objects:
interface Industry {
  name: string;
  description: string;
  image: string;
  id?: string; // for unique keys
}
  1. TODO Comment: Remove or address the TODO in data.ts before merging to production.

Summary of Action Items

Must Fix Before Merge:

  • Fix invalid Tailwind classes (p-0!!p-0, bg-linear-to-rbg-gradient-to-r)
  • Implement or remove the handleIndustryClick functionality
  • Fix the type mismatch in TextContentSection onClick handler
  • Address duplicate data issue and React key warnings
  • Document or fix the "buggy" loop behavior mentioned in comments

Should Fix:

  • Remove empty CSS rule block
  • Add unique IDs to industry objects
  • Add tests for new components
  • Improve accessibility with proper ARIA labels
  • Extract magic numbers to CSS variables

Nice to Have:

  • Add TypeScript interfaces for data structures
  • Consider mobile responsiveness
  • Review the layout change in page.tsx

Overall, this is a solid refactoring with good separation of concerns, but there are several functional issues that need to be addressed before merging. The code structure is much improved, but the implementation appears incomplete.

…s and add animation to industry text when it changes
@claude
Copy link

claude bot commented Jan 21, 2026

PR Review: Industries Carousel (TX-2341)

Summary

This PR refactors the solutions carousel from a single monolithic file into a modular component structure using Embla Carousel. Overall, the refactoring improves code organization and maintainability. However, there are several issues that should be addressed.


🔴 Critical Issues

1. Invalid Tailwind CSS Syntax

Location: src/app/home/solutions-carousel/TextContentSection.tsx:35,41

<div className="flex flex-col gap-8 min-w-[500px] max-w-[500px]!">
<Button className="flex items-center gap-6 p-0! overflow-visible h-full...">

Issue: The ! syntax (max-w-[500px]!, p-0!) is invalid Tailwind CSS. The correct syntax for important is to prefix with !, not suffix.

Fix:

  • max-w-[500px]!!max-w-[500px]
  • p-0!!p-0

2. Invalid Tailwind Class Name

Location: src/app/home/solutions-carousel/TextContentSection.tsx:43

className={`whitespace-nowrap bg-linear-to-r from-blue-400 to-blue-600...`}

Issue: bg-linear-to-r is not a valid Tailwind class. The correct class is bg-gradient-to-r.

Fix: bg-linear-to-rbg-gradient-to-r

3. Empty CSS Rule

Location: src/css/embla.css:13-14

.embla__viewport {
}

Issue: Empty CSS rule serves no purpose and should be removed.

4. Duplicate Data in Array

Location: src/app/home/solutions-carousel/data.ts:1-50

Issue: The industries array contains duplicated entries (lines 1-25 duplicated at lines 26-49), which doubles the carousel content unnecessarily. While there's a TODO comment indicating this is temporary, the key-related bug mentioned in index.tsx:56 stems from this duplication.

Impact:

  • Increases bundle size unnecessarily
  • Creates confusing UX with duplicate slides
  • Forces the use of array index in React keys (anti-pattern)

Recommendation: Remove duplicates now or use a proper unique ID for each industry record.


⚠️ Significant Issues

5. React Key Anti-Pattern

Location: src/app/home/solutions-carousel/index.tsx:56

key={`${industry.name}-${idx}`} // TODO: remove idx from key once we remove dups from data

Issue: Using array index in keys is an anti-pattern, especially in a carousel where items may reorder. This can cause React reconciliation bugs and performance issues.

Fix: Either:

  • Add unique IDs to each industry object
  • Use only industry.name as the key (if names are truly unique)
  • If loop mode requires duplicates, use a stable unique identifier

6. Non-Interactive Button

Location: src/app/home/solutions-carousel/TextContentSection.tsx:41-52

<Button className="flex items-center gap-6 p-0! overflow-visible h-full transition-all duration-300 bg-transparent hover:bg-transparent font-normal">

Issue: This Button has no onClick handler and appears to be used purely for styling. This is semantically incorrect and creates accessibility issues.

Fix: Replace with a <div> or properly styled element, or add the actual click handler if interaction is intended.

7. Unused State Variable

Location: src/app/home/solutions-carousel/useUnidirectionalEmbla.ts:9

const isBlockingRef = useRef(false);

Issue: isBlockingRef is set but never read, making it dead code.

Fix: Remove this ref if it's truly unused, or add the logic that depends on it.

8. Layout Shift Issue

Location: src/app/home/page.tsx:381

<section className="box-border ml-20 my-32">

Issue: Replacing page-width with box-border ml-20 changes the layout system. This hardcoded margin doesn't account for responsive design and may break on smaller screens.

Recommendation:

  • Verify this was intentional
  • Add responsive breakpoints if needed (e.g., ml-4 lg:ml-20)
  • Consider whether page-width should still be used for consistency

🟡 Code Quality & Best Practices

9. Missing Type Safety

Location: src/app/home/solutions-carousel/index.tsx:43

const currentIndustry = industries[selectedIdx % industries.length];

Issue: While this prevents out-of-bounds access, it assumes industries is never empty. Consider adding a safety check.

Suggestion:

const currentIndustry = industries[selectedIdx % industries.length] ?? industries[0];

10. Inconsistent Naming Convention

Location: src/app/home/solutions-carousel/index.tsx:46

Issue: Duplicated gap property in className:

className="flex flex-col xl:gap-20 xl:flex-row xl:items-center xl:gap-12"

The xl:gap-20 is immediately overridden by xl:gap-12. This appears to be a typo.

11. Magic Numbers in CSS

Location: src/css/embla.css:4-6,28

Issue: Several hardcoded values without clear context:

  • min-height: 40rem - Why 40rem specifically?
  • --slide-height: 19rem - Arbitrary value
  • transform: translateY(-60px) !important - Magic number + !important

Recommendation: Add CSS comments explaining these values or extract them into CSS custom properties with descriptive names.

12. Over-Use of !important

Location: src/css/embla.css:28

transform: translateY(-60px) !important;

Issue: Using !important suggests CSS specificity issues. Consider restructuring CSS to avoid this.


🟢 Performance Considerations

13. Plugin Configuration

Location: src/app/home/solutions-carousel/index.tsx:22

const plugins = [Autoplay(), ClassNames({ snapped: "is-snapped" })];

Issue: Plugins are recreated on every render. Should be memoized.

Fix:

const plugins = useMemo(() => [
  Autoplay(), 
  ClassNames({ snapped: "is-snapped" })
], []);

14. Missing Image Optimization

Location: src/app/home/solutions-carousel/data.ts

Issue: Using picsum.photos for placeholder images means:

  • External dependency for local development
  • No image optimization
  • Potential CORS issues

Recommendation:

  • For production, ensure real images are properly optimized
  • Consider using Next.js Image optimization features

✅ Positive Notes

  1. Good Separation of Concerns: Breaking the carousel into separate components (TextContentSection, useUnidirectionalEmbla) improves maintainability
  2. Custom Hook: The useUnidirectionalEmbla hook encapsulates complex pointer event logic nicely
  3. Proper Cleanup: Effect cleanup in useUnidirectionalEmbla properly removes event listeners
  4. Animation Timing: The text transition effect in TextContentSection is implemented cleanly with proper cleanup
  5. Next.js Config: Properly added image domain to allowed patterns

🔒 Security Concerns

15. External Image Sources

Location: next.config.ts:21-24, src/app/home/solutions-carousel/data.ts

Issue: Added picsum.photos to allowed image domains. While fine for development/placeholder, this should not go to production.

Recommendation: Ensure the TODO to switch to Figma assets (or proper CDN) is completed before production deployment.


🧪 Test Coverage

Missing: No tests were added for the new components. Consider adding:

  • Unit tests for TextContentSection animation logic
  • Tests for useUnidirectionalEmbla pointer event handling
  • Integration tests for carousel navigation

Summary of Required Changes

Must Fix Before Merge:

  1. Fix invalid Tailwind syntax (! suffix → prefix, bg-linear-to-rbg-gradient-to-r)
  2. Remove empty CSS rule
  3. Fix duplicate xl:gap values
  4. Replace Button with appropriate semantic element or add interaction
  5. Fix React key anti-pattern

Should Fix:
6. Remove duplicate data or add proper unique IDs
7. Add responsive breakpoints to ml-20
8. Memoize carousel plugins
9. Remove unused isBlockingRef or document its purpose

Nice to Have:
10. Add tests
11. Document magic numbers in CSS
12. Reduce !important usage
13. Add fallback for empty industries array


Great work on the refactor! The component structure is much cleaner. Please address the critical issues above and consider the recommendations.

@claude
Copy link

claude bot commented Jan 21, 2026

Pull Request Review: [FEAT] Industries Carousel (TX-2341)

Overview

This PR refactors the industries carousel component, replacing a custom implementation with an Embla-based carousel. The refactor improves code organization by splitting the monolithic component into smaller, focused modules.

Code Quality & Best Practices

✅ Strengths

  • Good separation of concerns: Breaking the carousel into index.tsx, TextContentSection.tsx, useUnidirectionalEmbla.ts, and data.ts follows React best practices
  • Custom hook pattern: The useUnidirectionalEmbla hook properly encapsulates the unidirectional scrolling logic
  • Proper cleanup: Event listeners are correctly removed in the useEffect cleanup function (lines 48-52 in useUnidirectionalEmbla.ts)
  • TypeScript typing: Good use of types for component props and Embla API

⚠️ Issues Found

1. Invalid CSS Class Syntax (src/app/home/solutions-carousel/TextContentSection.tsx:17)

<div className="flex flex-col gap-8 min-w-[500px] max-w-[500px]!">

The ! should be inside the bracket for important modifier: max-w-[500px] or use !max-w-[500px]. The current syntax is invalid.

2. Invalid Tailwind Class (TextContentSection.tsx:25)

className="...bg-linear-to-r from-blue-400..."

Should be bg-gradient-to-r, not bg-linear-to-r. This will not apply the gradient.

3. Button Accessibility Issue (TextContentSection.tsx:23)

The Button component wraps the industry name but has no onClick handler and no clear interactive purpose. This creates a non-functional button which is poor for accessibility. Either:

  • Remove the Button wrapper if it's not interactive
  • Add an onClick handler if it should be clickable
  • Use a different semantic element

4. Empty CSS Rule (src/css/embla.css:13-14)

.embla__viewport {
}

Empty CSS rules should be removed.

5. Duplicate Data (src/app/home/solutions-carousel/data.ts)

The industries array contains duplicate entries (lines 1-49). Each industry appears twice, which:

  • Increases bundle size unnecessarily
  • Creates confusion about the intended data structure
  • May cause the noted "loop bug" mentioned in the TODO comment

The comment on line 56 acknowledges this: // TODO: remove idx from key once we remove dups from data, related to loop bug on line 2

This workaround should be addressed. The duplicate data appears to be a temporary fix for the carousel loop behavior.

6. Key Prop Anti-pattern (index.tsx:56)

key={`${industry.name}-${idx}`}

Using index in keys with duplicate data can cause React reconciliation issues. Once duplicates are removed, use a unique identifier or the index alone.

7. Styling Inconsistency (src/app/home/page.tsx:381)

<section className="box-border ml-20 my-32">

Changed from page-width to box-border ml-20. This breaks consistency with other sections and uses a hardcoded margin instead of a semantic class. Consider whether this change is intentional or if it should use the page-width utility like other sections.

Performance Considerations

⚠️ Potential Issues

  1. Animation Conflicts: The custom CSS animation animate-fade-slide on TextContentSection may conflict with Embla's transitions, potentially causing janky animations
  2. Unnecessary Re-renders: TextContentSection receives activeIndustry which changes frequently. Consider memoization if performance issues arise
  3. Image Loading: Using external picsum.photos URLs without Next.js Image optimization dimensions. The height={600} width={600} props are set, which is good, but ensure images are optimized

✅ Good Practices

  • Proper use of React key prop for animations (lines 26, 36 in TextContentSection.tsx)
  • Event listener cleanup prevents memory leaks

Security Concerns

⚠️ Minor Issues

  1. External Image Sources: Using picsum.photos and placecats.com for production code

    • These are placeholder services and shouldn't be in production
    • The TODO comment indicates this is temporary, but ensure it's addressed before merging to production
    • Consider using a CDN or local assets for production
  2. Next.js Image Configuration: Adding external domains to remotePatterns is correct, but ensure these domains are trusted before production deployment

✅ Good Practices

  • Using Next.js Image component for optimized image loading
  • No unsafe inline styles or dangerouslySetInnerHTML usage

Test Coverage

❌ Critical Gap

No tests found for the new carousel implementation. Consider adding:

  • Unit tests for useUnidirectionalEmbla hook
  • Component tests for SolutionsCarousel
  • Integration tests for carousel navigation
  • Visual regression tests for animations

Additional Recommendations

  1. Complete the TODO items:

    • Remove duplicate data entries (data.ts:52)
    • Remove index from key prop (index.tsx:56)
    • Replace placeholder images with production assets
  2. Responsive Design: The hardcoded min-w-[500px] may cause issues on mobile. Test on small viewports.

  3. Documentation: Consider adding JSDoc comments for the custom hook to explain the unidirectional behavior

  4. CSS Organization: The CSS file is imported in page.tsx but only used in a nested component. Consider importing closer to usage or using CSS modules.

  5. Accessibility:

    • Add ARIA labels to carousel navigation
    • Ensure keyboard navigation works properly
    • Test with screen readers

Summary

This is a solid refactor that improves code organization. However, there are several critical issues that should be addressed before merging:

Must Fix:

  • Invalid CSS syntax (max-w-[500px]!)
  • Invalid Tailwind class (bg-linear-to-r)
  • Non-functional Button component
  • Duplicate data entries

Should Fix:

  • Add test coverage
  • Fix accessibility issues
  • Address all TODO comments

Nice to Have:

  • Improve responsive design
  • Add documentation
  • Consider performance optimizations

Overall: Needs revision before merging. The refactor direction is good, but the implementation has several bugs that need attention.

@claude
Copy link

claude bot commented Jan 21, 2026

Pull Request Review: Industries Carousel (TX-2341)

Overview

This PR refactors the solutions carousel component by breaking it into smaller, more maintainable modules and implementing Embla carousel with custom unidirectional scrolling behavior.


Code Quality & Best Practices

✅ Strengths

  • Good separation of concerns: Breaking the monolithic component into index.tsx, TextContentSection.tsx, data.ts, and useUnidirectionalEmbla.ts improves maintainability
  • Custom hook abstraction: useUnidirectionalEmbla encapsulates complex pointer event logic nicely
  • Type safety: Proper TypeScript usage with ActiveIndustry type and EmblaCarouselType

⚠️ Issues Found

1. Invalid Tailwind classes (src/app/home/solutions-carousel/TextContentSection.tsx:18, 24, 26)

<div className="flex flex-col gap-2 md:gap-8 md:min-w-[500px] md:max-w-[500px]!">
  • md:max-w-[500px]! - The ! syntax is invalid. Use !md:max-w-[500px] or md:!max-w-[500px]
  • p-0! on line 24 - Same issue, should be !p-0
  • bg-linear-to-r on line 26 - Invalid class, should be bg-gradient-to-r

2. Entire carousel is commented out (src/app/home/solutions-carousel/index.tsx:49-70)

The main carousel JSX is completely commented out, meaning:

  • The carousel doesn't render at all
  • emblaRef is defined but never used (line 23)
  • useUnidirectionalEmbla hook is called but has no effect
  • This appears to be incomplete work

3. Duplicate data (src/app/home/solutions-carousel/data.ts:1-49)

The industries array has duplicates (industries 1-4 are repeated twice). The comment mentions this is intentional for a "loop bug", but this is problematic:

  • Creates technical debt
  • Wastes memory
  • Confuses the data structure
  • The real issue should be fixed in the carousel configuration, not worked around with duplicate data

4. Unused variable (src/app/home/solutions-carousel/useUnidirectionalEmbla.ts:9)

const isBlockingRef = useRef(false);

This ref is set but never read, making it dead code.

5. Missing cleanup context (src/app/home/solutions-carousel/index.tsx:6)

Unused Image import from Next.js since the carousel is commented out.

6. Hardcoded pixel values (src/app/home/solutions-carousel/TextContentSection.tsx:18)

Comment acknowledges this: "dont want to hardcode pixels here" but then uses md:min-w-[500px] md:max-w-[500px]. Consider using Tailwind's semantic spacing or custom theme values.


Potential Bugs & Issues

🐛 Critical Issues

  1. Non-functional carousel: The entire carousel is commented out, so this feature doesn't work at all
  2. emblaApi might be undefined: Line 43 uses industries[selectedIdx % industries.length] where selectedIdx comes from emblaApi.selectedScrollSnap(), but if emblaApi is never initialized (carousel is commented), selectedIdx stays at 0

🐛 Moderate Issues

  1. Event listener memory leaks potential (useUnidirectionalEmbla.ts:44-47): While there is cleanup, the { passive: false } option on pointer events can cause performance issues on mobile devices
  2. Race condition: In the useEffect (index.tsx:28-41), onSelect() is called immediately after setting up the listener, but there's no guarantee emblaApi is fully initialized

Performance Considerations

⚡ Performance Issues

  1. Non-passive event listeners (useUnidirectionalEmbla.ts:44-45): Using { passive: false } on pointer events prevents browser scroll optimizations. Consider using passive listeners and only calling preventDefault() conditionally after checking deltaX.

  2. Animation on every render (TextContentSection.tsx:26, 36): The animate-fade-slide class triggers on key changes. With autoplay, this causes frequent animations that could impact performance.

  3. CSS in separate file (embla.css): While not necessarily bad, inline styles or CSS modules might provide better tree-shaking and code-splitting for this component-specific styling.

  4. Large Image URLs: Using picsum.photos without optimization. Next.js Image component helps, but ensure images are properly sized and use modern formats.


Security Concerns

🔒 Security Issues

  1. External image sources (next.config.ts:20-23):
{
  protocol: "https",
  hostname: "picsum.photos",
  pathname: "/**",
}
  • Allowing all paths from picsum.photos could be exploited if that domain is compromised
  • Consider using more restrictive pathname patterns or self-hosted images
  1. Figma asset URLs commented out (data.ts:54-82): The commented code shows Figma API URLs. These might contain sensitive asset IDs. Ensure these aren't publicly accessible or consider using a proxy.

  2. Missing alt text validation: No check that industry.name (used for alt text) is defined and non-empty.


Test Coverage

❌ No Tests Found

  • No test files exist for this feature
  • No unit tests for useUnidirectionalEmbla hook
  • No integration tests for carousel behavior
  • No accessibility tests

Recommendations:

  1. Add unit tests for useUnidirectionalEmbla to verify:
    • Backward scrolling is blocked
    • Forward scrolling works
    • Cleanup happens correctly
  2. Add component tests for SolutionsCarousel:
    • Verify correct industry displays
    • Test autoplay behavior
    • Test keyboard navigation
  3. Add accessibility tests:
    • Verify ARIA labels
    • Test keyboard controls
    • Check screen reader compatibility

Additional Recommendations

📝 Action Items

  1. Uncomment and complete the carousel implementation
  2. Fix the invalid Tailwind classes
  3. Remove duplicate industries data and fix the loop bug properly
  4. Remove unused isBlockingRef
  5. Add proper error boundaries around the carousel
  6. Add loading states for images
  7. Implement keyboard navigation (left/right arrows)
  8. Add ARIA labels for accessibility
  9. Consider adding tests before merging
  10. Update the TODO comments (page.tsx:380) with specific tasks or remove them
  11. Add TypeScript strict null checks for emblaApi

🎯 Priority Fixes Before Merge

  1. Fix invalid Tailwind syntax (breaks styling)
  2. Uncomment carousel or remove dead code
  3. Remove data duplication
  4. Add basic accessibility features

Summary

This PR shows good architectural direction with component decomposition, but appears to be incomplete work. The carousel is entirely commented out, making the feature non-functional. Additionally, there are several syntax errors and code quality issues that need addressing before merge.

Recommendation: Request changes - this needs completion and fixes before it's ready to merge.

@claude
Copy link

claude bot commented Jan 22, 2026

PR Review: Industries Carousel (TX-2341)

Overview

This PR refactors the solutions carousel by breaking it into modular components and implementing Embla carousel for better performance and maintainability. The code reorganization is positive, but there are several issues to address.


🐛 Critical Issues

1. Missing Animation Definition

Location: src/css/embla.css:67-69

.animate-fade-slide {
  animation: fadeSlide 300ms ease;
}

Issue: The fadeSlide keyframe animation is referenced but never defined. This will cause the animation to fail silently.

Fix: Add the keyframe definition:

@keyframes fadeSlide {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-fade-slide {
  animation: fadeSlide 300ms ease;
}

2. Invalid CSS Syntax

Location: src/app/home/solutions-carousel/TextContentSection.tsx:17

<div className="flex flex-col gap-2 md:gap-8 md:min-w-[50ch] md:max-w-[50ch]!">

Issue: The ! should be inside the brackets: md:max-w-[50ch!] or use !important syntax properly. However, Tailwind doesn't support !important this way for arbitrary values.

Fix: Remove the ! or restructure:

<div className="flex flex-col gap-2 md:gap-8 md:min-w-[50ch] md:max-w-[50ch]">

3. Invalid Tailwind Class

Location: src/app/home/solutions-carousel/TextContentSection.tsx:26

className="whitespace-nowrap bg-linear-to-r from-blue-400..."

Issue: bg-linear-to-r should be bg-gradient-to-r.

Fix:

className="whitespace-nowrap bg-gradient-to-r from-blue-400 to-blue-600..."

4. Button Styling Override Issues

Location: src/app/home/solutions-carousel/TextContentSection.tsx:23

<Button className="flex items-center gap-6 p-0!  h-full bg-transparent hover:bg-transparent font-normal">

Issues:

  • Invalid syntax: p-0! should be !p-0 or p-0 (extra space before exclamation)
  • Using <Button> as a styled container without proper semantics
  • No onClick handler or proper button functionality

Fix: Either remove the Button component or add proper interactivity:

<div className="flex items-center gap-6">
  {/* content */}
</div>

5. Duplicate Data for Loop Workaround

Location: src/app/home/solutions-carousel/data.ts:1-82

Issue: The industries array is duplicated (8 items instead of 4) as a workaround for a loop bug. This is a hack that should be addressed.

Recommendation:

  • Investigate the Embla loop bug properly
  • Consider if loop: true is actually needed
  • If loop is essential, document why duplication is necessary
  • The TODO comment acknowledges this, but it should be prioritized

⚠️ Code Quality Issues

6. Inconsistent Image Sources

Location: src/app/home/solutions-carousel/data.ts

The production Figma URLs are commented out and replaced with picsum.photos placeholder images. Ensure this is intentional and doesn't get deployed.

7. Commented Code

Location: next.config.ts:1

The old remotePatterns implementation was deleted, but there's a pattern of leaving TODOs. Consider cleaning these up before merge.

8. Unused Comment

Location: src/app/home/page.tsx:380

{/* TODO: make a set mx for mobile */}

This TODO is vague. Either implement the fix or create a ticket with more context.

9. Missing Comments in Complex Hook

Location: src/app/home/solutions-carousel/useUnidirectionalEmbla.ts

The custom hook implements pointer event blocking for backward scrolling but lacks documentation. Add JSDoc comments explaining the purpose and behavior.

10. Commented CSS

Location: src/css/embla.css:10

/* background-color: red; */

Remove debug code before merging.


🎯 Best Practices & Improvements

11. Component Naming Convention

The file is named TextContentSection.tsx but exports a default function. Consider either:

  • Using named export: export function TextContentSection()
  • Or matching filename to export: text-content-section.tsx

12. Type Safety

Location: src/app/home/solutions-carousel/TextContentSection.tsx:10-15

The ActiveIndustry type is defined locally but could be extracted and shared:

// types.ts or data.ts
export type Industry = {
  name: string;
  description: string;
  image: string;
};

13. Magic Numbers

Location: src/app/home/solutions-carousel/index.tsx:55

key={`${industry.name}-${idx}`} // TODO: remove idx from key once we remove dups

The TODO is tied to the data duplication issue. Prioritize fixing this.

14. CSS Organization

The Embla styles are added to a standalone embla.css file imported in src/app/page.tsx. Consider:

  • Moving to a CSS module: embla.module.css
  • Or integrating into the component with Tailwind
  • Document why this approach was chosen

15. Accessibility Concerns

Location: src/app/home/solutions-carousel/TextContentSection.tsx:23-31

The Button wrapping the industry name lacks:

  • Proper aria-label describing what clicking does
  • Visual focus indicators may be removed by custom styling
  • No actual click handler implemented

Fix:

<Button 
  className="..." 
  aria-label={`View details for ${activeIndustry.name}`}
  onClick={() => {/* handle click */}}
>

16. Next.js Image Optimization Not Used

Location: src/app/home/solutions-carousel/index.tsx:58-63

You're using <Image> from Next.js (good!) but the images come from picsum.photos which are placeholders. Ensure:

  • Production images are optimized
  • Proper alt text is descriptive (currently just uses industry.name)
  • Consider priority prop for above-fold images

🔒 Security

17. External Image Sources

Location: next.config.ts:18-23

Added picsum.photos to allowed domains. Ensure this is removed before production deployment, or document why it's needed.

18. No Input Validation

The carousel data is hardcoded, which is fine, but if this ever becomes dynamic, ensure proper validation and sanitization.


⚡ Performance

19. CSS Transition Performance

Location: src/css/embla.css:39

transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);

Using transform is good for performance (GPU-accelerated). Consider adding will-change: transform for smoother animations on active slides.

20. Event Listener Cleanup

Location: src/app/home/solutions-carousel/useUnidirectionalEmbla.ts:46-52

Cleanup is properly implemented. Good job! ✅


📊 Test Coverage

Issue: No test files found for the new components.

Recommendation: Add tests for:

  • SolutionsCarousel - rendering, autoplay behavior
  • TextContentSection - content display
  • useUnidirectionalEmbla - pointer event blocking logic
  • Keyboard navigation and accessibility

📝 Summary

Must Fix Before Merge:

  1. ✅ Add missing @keyframes fadeSlide animation
  2. ✅ Fix invalid CSS syntax: md:max-w-[50ch]!md:max-w-[50ch]
  3. ✅ Fix invalid class: bg-linear-to-rbg-gradient-to-r
  4. ✅ Fix button styling: p-0!!p-0
  5. ✅ Remove debug code (commented CSS)
  6. ✅ Clarify TODO or implement mobile margin fix

Should Fix:

  • Address the data duplication workaround
  • Add tests for new components
  • Improve accessibility (aria-labels, keyboard nav)
  • Document the custom hook behavior
  • Remove placeholder image service from production config

Nice to Have:

  • Extract shared types
  • Add JSDoc comments
  • Consider CSS module approach

Positive Notes 👍

  • Great refactoring from monolithic component to modular structure
  • Proper cleanup of event listeners in custom hook
  • Good use of Next.js Image component
  • Smooth transitions with GPU-accelerated properties
  • TypeScript usage throughout

Let me know if you'd like help addressing any of these issues!

@claude
Copy link

claude bot commented Jan 22, 2026

PR Review: Industries Carousel (TX-2341)

Overview

This PR refactors the solutions carousel from a custom implementation to use Embla Carousel with unidirectional scrolling behavior. The refactor includes splitting the component into smaller modules, upgrading to Embla v9.0.0-rc01, and implementing responsive styling.


Code Quality & Best Practices

Strengths:

  • Good separation of concerns: splitting carousel logic into index.tsx, TextContentSection.tsx, data.ts, and useUnidirectionalEmbla.ts
  • Custom hook (useUnidirectionalEmbla) follows React patterns well
  • Proper cleanup in useEffect hooks with return statements

Issues:

  1. Missing newline at end of file (package.json:82)

    • Remove the \ No newline at end of file - this should be fixed
  2. Commented code in production (src/app/home/page.tsx:178-188, data.ts:547-577)

    • Delete commented <CodeDemo> component instead of leaving it
    • Remove TODO comments and duplicate data arrays before merging
  3. Console.log left in code (index.tsx:647)

    console.log(tweenNodes.current);
    • Remove debug statements before merging
  4. Invalid Tailwind classes (TextContentSection.tsx:464, 470)

    className="md:min-w-[50ch] md:max-w-[50ch]!"  // Invalid !
    className="p-0!"  // Invalid !
    • The ! syntax is invalid. Use !p-0 or p-0 !important in CSS
  5. Invalid CSS class name (TextContentSection.tsx:472)

    className="bg-linear-to-r"  // Should be bg-gradient-to-r
  6. Hardcoded styles mixed with Tailwind

    • Comment on line 463 acknowledges hardcoded pixels - consider using Tailwind's max-w-prose or defining a custom max-width in Tailwind config

Potential Bugs & Issues

Critical:

  1. Duplicate data acknowledged but not fixed (data.ts:496-544)

    • Industries array contains exact duplicates (items 1-4 repeated as 5-8)
    • Comment says "TODO: delete above" but this should be resolved before merge
    • This affects carousel behavior and is related to the loop bug mentioned
  2. Known loop bug (index.tsx:611)

    loop: true, // for some reason this is buggy, but we need this
    • Acknowledged bug with loop functionality that may be related to duplicate data
    • Should be investigated and fixed rather than commented
  3. Incorrect array index handling (index.tsx:718)

    const currentIndustry = industries[selectedIdx % industries.length];
    • With duplicate data, this will cause incorrect mapping between selectedIdx and industry
  4. Index in React key (index.tsx:733)

    key={`${industry.name}-${idx}`} // TODO: remove idx from key once we remove dups
    • Using array index in keys is an anti-pattern, especially with duplicate names
    • This will cause React reconciliation issues

Moderate:

  1. Unsafe biome-ignore (index.tsx:702)

    // biome-ignore lint/correctness/useExhaustiveDependencies: <not needed>
    • Ignoring exhaustive dependencies without clear justification is risky
    • Should document why tweenScale, setTweenNodes, setTweenFactor don't need to be in deps
  2. Unidirectional scroll logic may have edge cases (useUnidirectionalEmbla.ts:784-792)

    • Blocking all positive deltaX might interfere with touch devices
    • The commented-out scrollTo suggests incomplete implementation
    • Consider testing on mobile devices thoroughly

Performance Considerations

  1. Using RC version in production (package.json:36-40)

    "embla-carousel": "9.0.0-rc01"
    • Using release candidate versions is risky for production
    • Consider waiting for stable v9.0.0 or stay on v8.x stable
  2. Image optimization concerns

    • Using picsum.photos placeholder images in production
    • Real images from Figma API should be used (as shown in TODO)
    • Consider using Next.js Image optimization fully
  3. CSS animations on every state change (TextContentSection.tsx:472-473)

    • animate-fade-slide runs on every industry change
    • The animation is defined but not shown in the diff - verify it's performant
  4. Tween calculations on every scroll event (index.tsx:654-700)

    • Complex calculations in scroll handler could impact performance
    • Consider throttling or using requestAnimationFrame

Security Concerns

  1. Remote image patterns added (next.config.ts:16-20)

    hostname: "picsum.photos"
    • Adding picsum.photos is fine for development but should be removed for production
    • Ensure only trusted domains are in production config
  2. No input validation

    • While carousel data is static, no validation for future dynamic data
    • Consider adding runtime checks if this will be CMS-driven

Test Coverage

Critical Issue:

  • No tests found in the repository
  • A refactor of this size should include:
    • Unit tests for useUnidirectionalEmbla hook
    • Integration tests for carousel behavior
    • Visual regression tests for responsive behavior
    • Accessibility tests for keyboard navigation

Recommendations:

  • Add tests before merging, especially for:
    • Unidirectional scroll blocking logic
    • Carousel state management
    • Responsive breakpoint behavior

Architecture & Design

Positives:

  • Modular structure with clear separation
  • Responsive design with mobile-first approach
  • Proper TypeScript types imported from Embla

Concerns:

  1. Migration to RC version without stability guarantee
  2. Unresolved TODOs and commented code suggest incomplete work
  3. Missing accessibility attributes (ARIA labels, keyboard navigation)

Action Items Before Merge

Must Fix:

  • Remove duplicate data from data.ts
  • Fix invalid Tailwind classes (! syntax)
  • Fix CSS class typo (bg-linear-to-rbg-gradient-to-r)
  • Remove console.log statements
  • Remove commented code blocks
  • Remove newline issue in package.json
  • Fix React keys (remove index usage)
  • Address loop bug or document why it's acceptable
  • Switch to real images from Figma (remove picsum.photos)

Should Fix:

  • Add test coverage
  • Document why exhaustive dependencies are ignored
  • Consider downgrading to Embla v8.x stable
  • Test unidirectional scroll on mobile devices
  • Add ARIA labels for accessibility
  • Verify tween animation performance

Nice to Have:

  • Extract hardcoded values to config
  • Add error boundaries
  • Document carousel behavior in comments

Summary

This is a solid refactor that improves code organization, but has several blocking issues:

  1. Duplicate data causing bugs
  2. Invalid CSS classes that will break styling
  3. Debug code left in (console.logs, TODOs)
  4. No tests for a major refactor
  5. RC version dependency risk

The architecture is good, but the implementation needs cleanup before merge. Address the "Must Fix" items and consider adding basic tests.

Recommendation: Request changes - fix blocking issues before approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants