Skip to content

Carousel for web - #30

Merged
dev-rathore merged 3 commits into
devfrom
feature/carousel-for-web
Nov 15, 2024
Merged

dev-rathore merged 3 commits into
devfrom
feature/carousel-for-web

Conversation

@dev-rathore

@dev-rathore dev-rathore commented Nov 15, 2024 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced CarouselNative and CarouselWeb components for enhanced media display.
    • Added RenderMediaItem component to handle rendering of images and videos.
  • Improvements

    • Streamlined media handling in the InfluencerCard component, simplifying state management and rendering logic.
    • Added a loading state with an ActivityIndicator for improved user feedback during media loading.
    • Updated styles for better alignment of media components.
    • Modified DrawerMenuContent to enhance layout and usability.

These changes enhance the user experience by providing a more intuitive and visually appealing media display.

@dev-rathore dev-rathore self-assigned this Nov 15, 2024
@coderabbitai

coderabbitai Bot commented Nov 15, 2024 •

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

Walkthrough

The pull request introduces significant modifications to the InfluencerCard.tsx component, primarily by removing unused imports and restructuring media rendering through a new CarouselNative component. State management has been simplified by eliminating several state variables and functions related to video playback and swiping. New components, including CarouselWeb and RenderMediaItem, have been added to enhance media display across platforms. Additionally, minor style adjustments were made to the InfluencerCard styles to improve layout alignment.

Changes

File Change Summary
components/InfluencerCard.tsx Removed unused imports; restructured media rendering with CarouselNative; simplified state management; replaced handleIndexChange with onImagePress.
components/ui/carousel/carousel.tsx Introduced CarouselNative component for swipeable media display; manages internal state and handles image press events.
components/ui/carousel/carousel.web.tsx Added CarouselWeb component utilizing Swiper for web media display; accepts data and onImagePress props.
components/ui/carousel/render-media-item.tsx New component RenderMediaItem to render images or videos based on type; includes tap handling and error management for video playback.
styles/InfluencerCard.styles.tsx Modified stylesFn to update media style by removing height and adding alignSelf: "center".
components/drawer-layout/DrawerMenuContent.tsx Replaced DrawerContentScrollView with ScrollView; adjusted layout and structure for improved content display.

Possibly related PRs

  • bug fixes #10: The changes in the InfluencerCard.tsx component regarding the handling of media items, particularly the handleIndexChange function, may relate to the main PR's modifications to the same component, which also involved media rendering logic.
  • Bug fix/UI feedback color changes #20: The updates to the InfluencerCard.tsx component, specifically the handling of media items and the renderMediaItem function, are relevant as they both focus on improving the media interaction features within the same component.
  • bug fixes #22: The routing logic changes in the onboarding-brand-preference.tsx and onboarding-your-brand.tsx files may not directly relate to the main PR but indicate a broader context of changes happening in the onboarding flow, which could be indirectly connected to the overall user experience improvements in the application.

Suggested reviewers

  • Manan-Sharma-5

🐰 In the meadow, bright and fair,
A card for influencers, with style and flair.
Media now dances, swipes with glee,
Tap to zoom in, come and see!
With a new carousel, oh what a delight,
Hopping through changes, all feels just right! 🌼✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Outside diff range and nitpick comments (8)
components/ui/carousel/render-media-item.tsx (2)

32-34: Consider memoizing styles for better performance.

The styles are recalculated on every render. Consider using useMemo to memoize the styles.

 const theme = useTheme();
-const styles = stylesFn(theme);
+const styles = React.useMemo(() => stylesFn(theme), [theme]);

35-59: Consider using a different resize mode for better image quality.

Using stretch as the resize mode might distort images. Consider using cover or contain for better image presentation.

           <Image
             source={{ uri: item.url || item.uri }}
             style={[
               styles.media,
               {
                 height: height || 250,
                 width: width || "100%",
               }
             ]}
-            resizeMode="stretch"
+            resizeMode="cover"
           />
components/ui/carousel/carousel.tsx (4)

25-25: Improve type safety for video references.

Consider using a more specific type for video refs:

const videoRefs = useRef<{ [key: number]: { seek: (time: number) => void } }>({});

34-34: Consider extracting magic number to a named constant.

The 150ms delay would be clearer as a named constant:

+const SWIPE_RESET_DELAY = 150; // milliseconds
-setTimeout(() => setIsSwiping(false), 150);
+setTimeout(() => setIsSwiping(false), SWIPE_RESET_DELAY);

55-56: Consider making dimensions responsive or configurable.

The hardcoded width and height might not work well across different screen sizes:

const PADDING = 45;
const ASPECT_RATIO = 16 / 9;

const width = Dimensions.get("window").width - PADDING;
const height = width / ASPECT_RATIO;

<Carousel
  width={width}
  height={height}
  {...}
/>

73-73: Add proper typing for indicator mapping.

Replace any with proper types:

-{data.map((_: any, index: any) => (
+{data.map((_: MediaItem, index: number) => (
components/InfluencerCard.tsx (2)

132-135: Consider adding error boundaries and loading states.

The CarouselNative implementation could benefit from:

  1. Error handling for failed media loads
  2. Loading states while media is being fetched
  3. Fallback UI for empty media arrays

Consider wrapping the carousel with error boundaries and adding loading states:

+        {influencer.media.length === 0 ? (
+          <View style={styles.noMediaContainer}>
+            <Text>No media available</Text>
+          </View>
+        ) : (
           <CarouselNative
             data={influencer.media}
             onImagePress={onImagePress}
+            onError={(error) => console.error('Carousel error:', error)}
+            loading={false} // Add loading prop
           />
+        )}

Line range hint 191-208: Enhance modal accessibility.

The modal implementation could benefit from accessibility improvements:

  1. Add appropriate ARIA labels
  2. Ensure keyboard navigation support
  3. Add screen reader support for zoom controls

Consider these accessibility enhancements:

 <Modal 
   visible={isZoomed} 
   transparent={true} 
   animationType="fade"
+  accessibilityLabel="Image zoom view"
+  accessibilityRole="dialog"
 >
   <View style={additionalStyles.modalContainer}>
     <TouchableOpacity
       style={additionalStyles.closeButton}
       onPress={() => {
         setIsZoomed(false);
         scale.value = 1;
       }}
+      accessibilityLabel="Close zoom view"
+      accessibilityHint="Double tap to close the zoomed image"
     >
       <Text style={additionalStyles.closeButtonText}>×</Text>
     </TouchableOpacity>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fa5287c and 32c5103.

📒 Files selected for processing (5)
  • components/InfluencerCard.tsx (5 hunks)
  • components/ui/carousel/carousel.tsx (1 hunks)
  • components/ui/carousel/carousel.web.tsx (1 hunks)
  • components/ui/carousel/render-media-item.tsx (1 hunks)
  • styles/InfluencerCard.styles.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
components/ui/carousel/carousel.tsx

[error] 36-36: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (6)
styles/InfluencerCard.styles.tsx (1)

62-62: LGTM! Verify layout stability with dynamic content.

The addition of alignSelf: "center" improves the media alignment flexibility. The removal of fixed height (per summary) allows for better content adaptability.

Let's verify the integration with CarouselNative and potential layout impacts:

✅ Verification successful

Based on the search results, I can now generate a final response as we have found important evidence about the media handling:

The alignSelf: "center" change is safe and properly supported

The CarouselNative component and its media rendering are properly handling dimensions:

  • The render-media-item.tsx component explicitly manages both height and width
  • Default height (250) and width (100%) are provided as fallbacks
  • The carousel component itself has proper dimension constraints

The removal of fixed height from InfluencerCard's media style is safe because:

  1. The parent carousel handles default dimensions
  2. The media rendering component has built-in dimension management
  3. The layout stability is maintained through the carousel's structure
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for CarouselNative implementation and related style properties
# Expected: Find CarouselNative component and verify it handles media dimensions

# Search for CarouselNative component implementation
echo "Searching for CarouselNative implementation..."
ast-grep --pattern 'const CarouselNative = $$$'

# Check for any explicit dimension handling in CarouselNative
echo "Checking dimension handling..."
rg -A 5 "CarouselNative.*style.*height|CarouselNative.*style.*width"

# Look for potential layout jump issues in related components
echo "Checking for layout stability measures..."
rg "onLayout|useLayout|measure" --type tsx

Length of output: 460


Script:

#!/bin/bash
# Let's try different approaches to find the CarouselNative component and related styles

# First, let's find all style files and components
echo "Searching for all style and component files..."
fd -e ts -e tsx -e js -e jsx

# Then search for CarouselNative references
echo "Searching for CarouselNative references..."
rg "CarouselNative" -l

# Look for style definitions and dimension handling in any file
echo "Checking style definitions and dimension handling..."
rg "StyleSheet.create.*media|style.*media" -A 5

# Check for layout-related props and handlers
echo "Checking layout handlers..."
rg "onLayout|Layout|measure|height|width" --type ts --type js

Length of output: 18211

components/ui/carousel/render-media-item.tsx (3)

1-14: LGTM! Imports are well-organized and necessary.

All imports are being used appropriately in the component.


24-31: LGTM! Clean component declaration.

The component declaration and props destructuring follow React best practices.


91-91: LGTM! Clean export.

The component export follows standard practices.

components/InfluencerCard.tsx (2)

54-55: LGTM! State management simplified.

The removal of media-related states (currentIndex, muted, isPlaying, isSwiping) and delegation to CarouselNative component improves code maintainability.


26-26: Verify CarouselNative component implementation.

Let's ensure the CarouselNative component exists and is properly implemented.

✅ Verification successful

CarouselNative component is properly implemented

The CarouselNative component exists at the correct location and is properly implemented with:

  • A functional React component using react-native-reanimated-carousel
  • Proper type definitions and props interface
  • Media rendering capabilities through RenderMediaItem
  • Carousel controls and state management for images/videos
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if CarouselNative component exists and verify its implementation
fd -e tsx -e ts "carousel.tsx" components/ui/carousel/

Length of output: 90


Script:

#!/bin/bash
# Check the implementation of CarouselNative component
cat components/ui/carousel/carousel.tsx

Length of output: 2244

Comment on lines +19 to +20
const swiperRef = useRef<Swiper>(null);
const videoRefs = useRef<{ [key: number]: any }>({});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve ref management and error handling

Several improvements can be made to the component's implementation:

  1. The videoRefs are created but there's no cleanup logic
  2. The image press handler lacks error handling

Consider these improvements:

 const CarouselWeb: React.FC<CarouselWebProps> = ({
   data,
   onImagePress,
 }) => {
   const theme = useTheme();
   const styles = stylesFn(theme);
   const swiperRef = useRef<Swiper>(null);
   const videoRefs = useRef<{ [key: number]: any }>({});
+
+  useEffect(() => {
+    return () => {
+      // Cleanup video refs
+      Object.values(videoRefs.current).forEach(videoRef => {
+        if (videoRef?.pause) {
+          videoRef.pause();
+        }
+      });
+      videoRefs.current = {};
+    };
+  }, []);

   const handleImagePress = (uri: string) => {
+    if (!uri) {
+      console.error('Invalid image URI');
+      return;
+    }
     if (onImagePress) {
       onImagePress(uri);
     }
   };

Also applies to: 22-26

Comment on lines +1 to +7
import React, { useRef } from "react";
import Swiper from "react-native-swiper";
import stylesFn from "@/styles/tab1.styles";
import { useTheme } from "@react-navigation/native";
import Colors from "@/constants/Colors";
import RenderMediaItem from "./render-media-item";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Review platform-specific dependencies

The component is using react-native-swiper in a web-specific file (.web.tsx). This might cause compatibility issues as React Native components may not work correctly in a web environment.

Consider using a web-specific carousel library like react-slick or swiper.js. Example implementation:

-import Swiper from "react-native-swiper";
+import { Swiper, SwiperSlide } from 'swiper/react';
+import 'swiper/css';

Organize styles in a more maintainable way

The styles are imported from tab1.styles, which suggests they might be tightly coupled with a specific tab implementation.

Consider moving carousel-specific styles to a dedicated styles file like carousel.styles.ts for better maintainability and reusability.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +8 to +11
interface CarouselWebProps {
data: any
onImagePress: (data: any) => void;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper TypeScript types

The interface uses any type which reduces type safety. Define proper types for the data structure and callback parameters.

Consider using more specific types:

+interface MediaItem {
+  id?: string | number;
+  uri: string;
+  type: 'image' | 'video';
+}

 interface CarouselWebProps {
-  data: any;
-  onImagePress: (data: any) => void;
+  data: MediaItem[];
+  onImagePress: (uri: string) => void;
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +28 to +57
return (
<Swiper
ref={swiperRef}
height={560}
style={styles.wrapper}
dotStyle={styles.dotStyle}
activeDotStyle={[
styles.dotStyle,
{
backgroundColor: Colors(theme).primary,
},
]}
paginationStyle={styles.pagination}
>
{data.map((
item: any,
index: number,
) => (
<RenderMediaItem
handleImagePress={handleImagePress}
height={560}
index={index}
item={item}
key={item.id || index}
videoRefs={videoRefs}
/>
))}
</Swiper>
);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility and responsiveness

The carousel implementation needs improvements in several areas:

  1. Hardcoded height might not work well across different screen sizes
  2. Missing accessibility attributes
  3. No loading or error states

Consider these improvements:

 <Swiper
   ref={swiperRef}
-  height={560}
+  height="100%"
+  style={[styles.wrapper, { minHeight: 300, maxHeight: 560 }]}
   style={styles.wrapper}
   dotStyle={styles.dotStyle}
+  aria-label="Media carousel"
+  keyboard={true}
   activeDotStyle={[
     styles.dotStyle,
     {
       backgroundColor: Colors(theme).primary,
     },
   ]}
   paginationStyle={styles.pagination}
 >
   {data.map((
     item: any,
     index: number,
   ) => (
     <RenderMediaItem
       handleImagePress={handleImagePress}
-      height={560}
+      height="100%"
       index={index}
       item={item}
       key={item.id || index}
       videoRefs={videoRefs}
+      onError={(error) => console.error(`Failed to load media item ${index}:`, error)}
     />
   ))}
 </Swiper>

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +1 to +59
import React, { useRef } from "react";
import Swiper from "react-native-swiper";
import stylesFn from "@/styles/tab1.styles";
import { useTheme } from "@react-navigation/native";
import Colors from "@/constants/Colors";
import RenderMediaItem from "./render-media-item";

interface CarouselWebProps {
data: any
onImagePress: (data: any) => void;
};

const CarouselWeb: React.FC<CarouselWebProps> = ({
data,
onImagePress,
}) => {
const theme = useTheme();
const styles = stylesFn(theme);
const swiperRef = useRef<Swiper>(null);
const videoRefs = useRef<{ [key: number]: any }>({});

const handleImagePress = (uri: string) => {
if (onImagePress) {
onImagePress(uri);
}
};

return (
<Swiper
ref={swiperRef}
height={560}
style={styles.wrapper}
dotStyle={styles.dotStyle}
activeDotStyle={[
styles.dotStyle,
{
backgroundColor: Colors(theme).primary,
},
]}
paginationStyle={styles.pagination}
>
{data.map((
item: any,
index: number,
) => (
<RenderMediaItem
handleImagePress={handleImagePress}
height={560}
index={index}
item={item}
key={item.id || index}
videoRefs={videoRefs}
/>
))}
</Swiper>
);
};

export default CarouselWeb;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codebase verification

Platform-specific carousel implementation needs adjustment

The verification revealed several issues that need attention:

  • The web carousel imports styles from @/styles/tab1.styles which doesn't exist in the expected locations
  • The InfluencerCard component currently uses CarouselNative but lacks platform-specific handling for web
  • The styles referenced in CarouselWeb (wrapper, pagination, dotStyle) are not properly defined

Required changes:

  • Move styles to a shared location or create platform-specific style files
  • Add platform-specific import logic in InfluencerCard to use CarouselWeb for web platform
  • Ensure style definitions are available and consistent across platforms
🔗 Analysis chain

Verify integration with InfluencerCard component

Since this is a new web-specific carousel implementation, ensure it integrates correctly with the parent component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check usage of CarouselWeb in InfluencerCard
rg -l "CarouselWeb" --type tsx

# Check for any existing carousel implementations that might conflict
rg -l "Carousel" --type tsx

# Check for responsive design implementations
ast-grep --pattern 'style={[^}]*height'

Length of output: 156


Script:

#!/bin/bash
# Check usage of CarouselWeb component
rg -l "CarouselWeb"

# Check for any existing carousel implementations
rg -l "Carousel"

# Check the parent component's integration
rg -A 5 "import.*CarouselWeb"

# Look for style definitions that might affect responsive design
rg "wrapper|pagination|dotStyle" tab1.styles

Length of output: 313


Script:

#!/bin/bash
# Check how CarouselWeb is used in InfluencerCard
rg -A 10 "CarouselWeb" components/InfluencerCard.tsx

# Check the base carousel implementation
cat components/ui/carousel/carousel.tsx

# Look for style definitions in the correct path
rg "wrapper|pagination|dotStyle" components/ui/carousel/

Length of output: 2645


Script:

#!/bin/bash
# Check the styles import path
cat components/styles/tab1.styles.ts 2>/dev/null || cat styles/tab1.styles.ts 2>/dev/null

# Check if there are any platform-specific imports or conditionals
rg -A 5 "Platform.select|Platform.OS" components/ui/carousel/

# Check the actual usage in InfluencerCard to see platform handling
rg -B 5 -A 15 "import.*Carousel" components/InfluencerCard.tsx

Length of output: 1185

Comment on lines +61 to +88
return (
<Video
ref={(ref) => {
if (ref && videoRefs) {
videoRefs.current[index] = ref;
}
}}
source={
item.appleUrl
? {
uri: Platform.OS === "ios" ? item.appleUrl : item.playUrl,
}
: require("@/assets/videos/ForBiggerJoyrides.mp4")
}
style={[
styles.media,
{
height: height || 250,
width: width || "100%",
}
]}
resizeMode={ResizeMode.COVER}
isLooping={false}
shouldPlay={false}
useNativeControls
onError={(error) => console.log("Video Error:", error)}
/>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Several improvements needed in video handling.

  1. The hardcoded fallback video path creates a tight coupling. Consider making it configurable.
  2. Error handling should use proper error logging/reporting.
  3. Video ref type should be properly typed.
+import { Video as ExpoVideo } from 'expo-av';
+
+interface VideoRefs {
+  [key: number]: ExpoVideo | null;
+}

 interface RenderMediaItemProps {
   // ...
-  videoRefs?: React.MutableRefObject<{ [key: number]: any }>;
+  videoRefs?: React.MutableRefObject<VideoRefs>;
   // ...
 }

 // Later in the code:
       source={
         item.appleUrl
           ? {
             uri: Platform.OS === "ios" ? item.appleUrl : item.playUrl,
           }
-          : require("@/assets/videos/ForBiggerJoyrides.mp4")
+          : props.fallbackVideo // Add this to props
       }
       // ...
-      onError={(error) => console.log("Video Error:", error)}
+      onError={(error) => {
+        // Use your app's error reporting mechanism
+        reportError('Video playback error', error);
+      }}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +15 to +22
interface RenderMediaItemProps {
handleImagePress: (uri: string) => void;
height?: number;
index: number;
item: any;
videoRefs?: React.MutableRefObject<{ [key: number]: any }>;
width?: number;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define proper types for the media item instead of using 'any'.

Using any type reduces type safety. Consider creating a proper type definition for the media item.

+interface MediaItem {
+  type: 'image' | 'video';
+  uri?: string;
+  url?: string;
+  appleUrl?: string;
+  playUrl?: string;
+}

 interface RenderMediaItemProps {
   handleImagePress: (uri: string) => void;
   height?: number;
   index: number;
-  item: any;
+  item: MediaItem;
   videoRefs?: React.MutableRefObject<{ [key: number]: any }>;
   width?: number;
 }
📝 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
interface RenderMediaItemProps {
handleImagePress: (uri: string) => void;
height?: number;
index: number;
item: any;
videoRefs?: React.MutableRefObject<{ [key: number]: any }>;
width?: number;
}
interface MediaItem {
type: 'image' | 'video';
uri?: string;
url?: string;
appleUrl?: string;
playUrl?: string;
}
interface RenderMediaItemProps {
handleImagePress: (uri: string) => void;
height?: number;
index: number;
item: MediaItem;
videoRefs?: React.MutableRefObject<{ [key: number]: any }>;
width?: number;
}

Comment on lines +12 to +15
interface CarouselProps {
data: any[]; // TODO: Add specific type
onImagePress?: (data: any) => void;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace any type with a proper interface definition.

The any type reduces type safety. Based on the component's usage, consider defining a proper type:

interface MediaItem {
  uri: string;
  type: 'image' | 'video';
  thumbnail?: string;
}

interface CarouselProps {
  data: MediaItem[];
  onImagePress?: (uri: string) => void;
}

Comment on lines +35 to +41
Object.values(videoRefs.current).forEach((videoRef) => {
if (videoRef && videoRef.seek) {
videoRef.seek(0);
setIsPlaying(false);
}
});
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve video ref handling with optional chaining and cleanup.

The video ref access could be safer and should be cleaned up on unmount:

// Inside component:
useEffect(() => {
  return () => {
    // Cleanup video refs on unmount
    Object.values(videoRefs.current).forEach((videoRef) => {
      videoRef?.seek?.(0);
    });
  };
}, []);

// In handleIndexChange:
Object.values(videoRefs.current).forEach((videoRef) => {
  videoRef?.seek?.(0);
  setIsPlaying(false);
});
🧰 Tools
🪛 Biome

[error] 36-36: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Comment on lines +94 to +97
const onImagePress = (data: any) => {
setSelectedImage(data); // TODO: data -> uri
setIsZoomed(true);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve type safety in onImagePress handler.

The any type and TODO comment suggest room for improvement:

  1. The parameter type should be more specific
  2. The TODO comment should be addressed

Consider this improvement:

-  const onImagePress = (data: any) => {
-    setSelectedImage(data); // TODO: data -> uri
+  const onImagePress = (uri: string) => {
+    setSelectedImage(uri);

Committable suggestion skipped: line range outside the PR's diff.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
components/InfluencerCard.tsx (1)

148-151: Add error handling for media loading failures

The carousel implementation lacks error boundaries and fallback UI for media loading failures. This could lead to a poor user experience if media fails to load.

Consider adding error handling:

   <CarouselNative
     data={influencer.media}
     onImagePress={onImagePress}
+    onError={(error) => console.error('Media loading failed:', error)}
+    fallbackComponent={
+      <View style={styles.mediaFallback}>
+        <Text>Failed to load media</Text>
+      </View>
+    }
   />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 32c5103 and 96b67a3.

📒 Files selected for processing (1)
  • components/InfluencerCard.tsx (5 hunks)
🔇 Additional comments (1)
components/InfluencerCard.tsx (1)

27-27: Verify CarouselNative component implementation

The import suggests a local carousel component. Let's verify its implementation and ensure it handles all the media types properly.

✅ Verification successful

CarouselNative component is properly implemented with platform-specific handling

The import in InfluencerCard.tsx is correct and the component exists with proper implementation:

  • Native version uses react-native-reanimated-carousel
  • Web version uses react-native-swiper
  • Both versions handle media items through a shared RenderMediaItem component
  • Proper handling of image press events and video refs
  • Platform-specific styling and dimensions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the CarouselNative component exists and verify its implementation
ast-grep --pattern 'export $_ function CarouselNative' ./components/ui/carousel/carousel.tsx

# Check for media type handling in the component
rg -A 10 'type.*=.*string' ./components/ui/carousel/carousel.tsx

Length of output: 161


Script:

#!/bin/bash
# Let's try different approaches to locate the carousel component

# First, let's check if the file exists with different extensions
fd "carousel" components/ui/carousel/

# If not found in that specific path, search more broadly for carousel-related files
fd "carousel" components/

# Look for any exports containing "Carousel" in case the component name is different
rg -l "export.*Carousel" components/

# Search for carousel-related imports to trace its usage
rg -l "import.*[Cc]arousel" components/

Length of output: 462


Script:

#!/bin/bash
# Let's examine the carousel implementation
cat components/ui/carousel/carousel.tsx

# Also check the web version to understand the platform-specific implementation
cat components/ui/carousel/carousel.web.tsx

Length of output: 3648

Comment on lines +101 to +109
useEffect(() => {
const timer = setTimeout(() => {
setLoading(false);
}, 1000);

const renderMediaItem = ({ item, index }: any) => {
if (item.type === "image") {
return (
<TapGestureHandler
onHandlerStateChange={({ nativeEvent }) => {
if (nativeEvent.state === State.ACTIVE) {
handleImagePress(item.uri);
}
}}
>
<Animated.View>
<Image
source={{ uri: item.url || item.uri }}
style={styles.media}
/>
</Animated.View>
</TapGestureHandler>
);
} else {
return (
<Video
ref={(ref) => {
if (ref) {
videoRefs.current[index] = ref;
}
}}
source={
item.appleUrl
? {
uri: Platform.OS === "ios" ? item.appleUrl : item.playUrl,
}
: require("../assets/videos/ForBiggerJoyrides.mp4")
}
style={styles.media}
resizeMode={ResizeMode.COVER}
isLooping={false}
shouldPlay={false}
useNativeControls
onError={(error) => console.log("Video Error:", error)}
/>
);
}
};
return () => {
clearTimeout(timer);
};
}, []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve loading state implementation

The current implementation uses a fixed 1-second timeout which might not reflect actual media loading times. This could lead to:

  1. Showing loading spinner even after content is ready
  2. Hiding loading spinner before content is fully loaded

Consider implementing actual loading state tracking:

-  const [loading, setLoading] = useState(true);
+  const [mediaLoading, setMediaLoading] = useState(true);
 
-  useEffect(() => {
-    const timer = setTimeout(() => {
-      setLoading(false);
-    }, 1000);
-
-    return () => {
-      clearTimeout(timer);
-    };
-  }, []);
-
-  if (loading) {
+  if (mediaLoading) {
     return <ActivityIndicator />;
   }

Then pass the loading state handler to CarouselNative:

   <CarouselNative
     data={influencer.media}
     onImagePress={onImagePress}
+    onLoadComplete={() => setMediaLoading(false)}
   />

Also applies to: 111-113

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.

2 participants