Repository navigation
Theme update and code refactoring - #33
Conversation
* feedbacks resolved
* carousel for web changes * crash scenario * drawer ui improvement
* theme updated and code refactoring
WalkthroughThe pull request introduces a series of modifications across multiple files, primarily focusing on the removal of the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant Backend
User->>App: Sign Up
App->>Backend: Create Account
Backend-->>App: Account Created
App-->>User: Show Confirmation
Possibly related PRs
Suggested reviewers
Poem
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 66
🧹 Outside diff range and nitpick comments (124)
utils/conversion.ts (1)
1-6: Consider enhancing for broader application usageSince this is a utility function used across components, consider these improvements:
- Support for larger units (M, B)
- Configurable decimal places
- Explicit return type
-export const convertToKUnits = (num: number) => { +export const convertToKUnits = ( + num: number, + decimalPlaces: number = 1 +): string => { + if (!Number.isFinite(num)) return 'N/A'; + + const units = ['', 'k', 'M', 'B']; + const absNum = Math.abs(num); + const unitIndex = absNum === 0 ? 0 : Math.floor(Math.log10(absNum) / 3); + + if (unitIndex === 0) return num.toString(); + + const sign = num < 0 ? '-' : ''; + const value = absNum / Math.pow(1000, unitIndex); + return `${sign}${value.toFixed(decimalPlaces)}${units[unitIndex]}`; };styles/tag/Tag.styles.tsx (3)
1-3: Consider using type imports for better type safetySince
Themeis a type, it should be imported using thetypekeyword to ensure it's removed during compilation and to make the type dependencies explicit.import { StyleSheet } from "react-native"; -import { Theme } from "@react-navigation/native"; +import type { Theme } from "@react-navigation/native"; import Colors from "@/constants/Colors";
5-16: Add TypeScript return type annotation for better type safetyThe
stylesFnfunction should have an explicit return type annotation for better type safety and documentation.-export const stylesFn = (theme: Theme) => StyleSheet.create({ +export const stylesFn = (theme: Theme): ReturnType<typeof StyleSheet.create> => StyleSheet.create({
12-15: Consider extracting magic numbers to constantsThe font size and border radius values are hardcoded. Consider extracting these to a constants file or theme configuration for better maintainability and consistency across the application.
tagText: { - fontSize: 12, + fontSize: theme.fonts?.regular?.fontSize ?? 12, color: Colors(theme).tagForeground, + flexShrink: 1, },components/ui/tag/index.tsx (3)
5-8: Consider adding prop types documentationWhile the component inherits ChipProps, adding JSDoc comments would improve component discoverability and usage understanding.
+/** + * A themed tag component wrapping react-native-paper's Chip + * @param {ChipProps} props - All props supported by react-native-paper's Chip component + */ const Tag: React.FC<ChipProps> = ({
13-19: Consider memoizing the component for performanceSince this is a UI component that might be rendered frequently in lists or grids, consider wrapping it with React.memo to prevent unnecessary re-renders.
-const Tag: React.FC<ChipProps> = ({ +const Tag: React.FC<ChipProps> = React.memo(({ children, ...props -}) => { +}) => { const theme = useTheme(); const styles = stylesFn(theme); return ( <Chip style={styles.tag} textStyle={styles.tagText} {...props} > {children} </Chip> ); -}; +});
14-16: Consider making styles customizableThe component could be more flexible by allowing style overrides while maintaining default themed styles.
<Chip - style={styles.tag} - textStyle={styles.tagText} + style={[styles.tag, props.style]} + textStyle={[styles.tagText, props.textStyle]} {...props} >styles/Proposal.styles.tsx (1)
19-19: Great improvement using theme-based color!Replacing the hardcoded RGB value with
Colors(theme).primaryenhances maintainability and consistency with the theming system.This change promotes better maintainability by:
- Centralizing color management
- Supporting dynamic theme changes
- Ensuring consistent color usage across the application
styles/brand-item/BrandItem.styles.tsx (1)
15-15: LGTM! Consider documenting the padding increaseThe increased vertical padding (12px) improves component spacing and touch targets. Consider adding a comment explaining the rationale for future maintainers.
borderBottomColor: Colors(theme).aliceBlue, paddingLeft: 14, paddingRight: 8, + // Increased padding for better touch targets and visual spacing paddingVertical: 12,styles/empty-state/EmptyState.styles.tsx (1)
20-21: Consider using responsive dimensions for different screen sizes.While the fixed maximum dimensions work well, you might want to consider using responsive values (e.g., percentage of screen width) for better adaptability across different device sizes.
image: { borderRadius: 10, - maxWidth: 256, - maxHeight: 256, + maxWidth: '70%', + maxHeight: 256, },utils/url.ts (1)
3-6: Enhance URL validation logic.The current URL validation is basic and might allow invalid URLs. Consider using a more robust URL validation approach.
if ( image && typeof image === "string" && - (image.startsWith("http") || image.startsWith("ph://")) + ( + /^https?:\/\/.+/.test(image) || + /^ph:\/\/.+/.test(image) + ) ) {constants/Themes/Theme.ts (1)
18-20: Consider expanding the elevation systemThe current elevation system only defines
level1. For a more comprehensive Material Design implementation, consider adding more elevation levels.elevation: { level1: Colors(theme).white, + level2: Colors(theme).white, + level3: Colors(theme).white, + level4: Colors(theme).white, + level5: Colors(theme).white, },This would provide more flexibility for different surface elevations in your UI components.
components/collaborations/index.tsx (3)
1-5: Consider using absolute imports consistently.The relative import path
../ui/top-tab-navigationcould be replaced with an absolute import@/components/ui/top-tab-navigationto maintain consistency with other imports.-import TopTabNavigation from "../ui/top-tab-navigation"; +import TopTabNavigation from "@/components/ui/top-tab-navigation";
7-18: Consider optimizing component rendering and adding type safety.
- Directly instantiating components in the tabs configuration might cause unnecessary re-renders.
- Adding TypeScript interfaces would improve type safety and maintainability.
Consider this improvement:
interface Tab { id: string; title: string; component: React.ComponentType; } const tabs: Tab[] = [ { id: "Active", title: "Active", component: Applications, }, { id: "Past", title: "Past", component: Invitations, }, ]; // In TopTabNavigation, render the component like: // const Component = tab.component; // return <Component />;
20-34: Implementation looks good with minor suggestions.The component is well-structured and follows React best practices. Consider these minor improvements:
- Add proper prop types definition for the component
- Consider using theme-based spacing instead of hardcoded padding values
Example improvement:
interface CollaborationsProps { // Add any props if needed in the future } const Collaborations: React.FC<CollaborationsProps> = () => { return ( <AppLayout> <View style={{ flex: 1, paddingTop: theme.spacing.medium, // Use theme-based spacing }} > <TopTabNavigation tabs={tabs} /> </View> </AppLayout> ); };components/contracts/index.tsx (2)
1-4: Consider adding TypeScript interface for component propsThe imports look good, but since this is a TypeScript file, it would be beneficial to define explicit types for the component's props (if any are planned to be added in the future).
interface ContractsProps { // Add any future props here }
22-24: Implement contract list viewThe current implementation for displaying contracts is a placeholder. Consider implementing a proper list view with contract details.
Would you like me to help create a basic contract list implementation with proper TypeScript types and styling?
styles/NotificationCard.styles.tsx (1)
16-19: Consider shadow visibility impactWhile the padding and border radius changes improve the card's appearance, setting
shadowColorto transparent removes the visual depth. This might affect:
- Visual hierarchy
- Card distinction from background
- Accessibility (visual separation)
Consider maintaining a subtle shadow for better visual distinction.
- shadowColor: Colors(theme).transparent, + shadowColor: Colors(theme).text, + shadowOpacity: 0.1, + shadowOffset: { width: 0, height: 2 }, + shadowRadius: 4, + elevation: 3, // for Androidlayouts/app-layout/index.tsx (1)
27-27: Consider Toast positioning and z-index handling.While centralizing Toast in AppLayout is a good architectural decision, placing it within SafeAreaView might cause positioning issues on some devices, especially with full-screen modals or keyboards.
Consider these improvements:
- Move Toast outside SafeAreaView to ensure it's always visible
- Add appropriate z-index styling
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => { const theme = useTheme(); const isAndroid = useMemo(() => Platform.OS === "android", []); return ( - <SafeAreaView - style={[ - styles.container, - { - backgroundColor: Colors(theme).background, - paddingTop: isAndroid ? StatusBar.currentHeight : 0, - }, - ]} - > - {children} - <ExpoStatusBar style={!theme.dark ? "dark" : "light"} /> - <Toast /> - </SafeAreaView> + <> + <SafeAreaView + style={[ + styles.container, + { + backgroundColor: Colors(theme).background, + paddingTop: isAndroid ? StatusBar.currentHeight : 0, + }, + ]} + > + {children} + <ExpoStatusBar style={!theme.dark ? "dark" : "light"} /> + </SafeAreaView> + <Toast topOffset={isAndroid ? StatusBar.currentHeight : 0} /> + </> ); };app/(main)/(screens)/collaboration-details/[pageID].tsx (1)
9-10: Consider creating a typed variable for pageIDTo improve type safety and reduce repetition, consider extracting the type-cast pageID into a variable.
const [isVisible, setIsVisible] = useState(false); - const pageID = useLocalSearchParams().pageID; + const { pageID } = useLocalSearchParams(); + const typedPageID = pageID as string;Then use
typedPageIDin the component props to avoid repeated type casting.styles/collaboration-details/CollaborationHeader.styles.tsx (2)
5-10: Consider extracting magic numbers to constants.While the styles are well-structured, consider extracting the hardcoded values (16, 600) to named constants. This would improve maintainability and make it easier to maintain consistent spacing across the app.
+const SPACING = { + DEFAULT: 16, + CONTAINER_MAX_WIDTH: 600, +}; + export const stylesFn = (theme: Theme) => StyleSheet.create({ container: { - paddingHorizontal: 16, - paddingBottom: 16, - maxWidth: 600, + paddingHorizontal: SPACING.DEFAULT, + paddingBottom: SPACING.DEFAULT, + maxWidth: SPACING.CONTAINER_MAX_WIDTH, },
25-38: Consider using typography constants for better consistency.While the theme-aware colors are good, consider:
- Using a typography system with semantic constants for font sizes
- Using semantic font weights (e.g., 'bold' instead of '600') for better readability
+const TYPOGRAPHY = { + HEADING: 18, + BODY: 14, +}; title: { - fontSize: 18, - fontWeight: '600', + fontSize: TYPOGRAPHY.HEADING, + fontWeight: 'bold', color: Colors(theme).text, },components/ui/menu-icon/index.tsx (2)
Line range hint
2-2: Remove unused FontAwesome importThe
FontAwesomeimport from@expo/vector-iconsis no longer used after switching to@fortawesome/react-native-fontawesome.-import { FontAwesome } from "@expo/vector-icons";Also applies to: 7-8
23-26: Consider adding accessibility labelThe icon implementation looks good, but since this is a navigation element, consider adding an accessibility label for screen readers.
<FontAwesomeIcon color={Colors(theme).text} icon={faNavicon} size={24} + accessibilityLabel="Open menu" style={{ zIndex: 0, opacity: pressed ? 0.5 : 1, }} />styles/CollaborationCard.styles.tsx (1)
51-52: LGTM! Modern spacing approachUsing the
gapproperty is a cleaner approach to spacing elements compared to individual margins. However, consider adding a comment explaining the spacing values for better maintainability.chipRow: { flexDirection: "row", flexWrap: "wrap", + // Vertical spacing from other elements marginTop: 12, + // Consistent spacing between chips gap: 16, },styles/top-tab-navigation/TopTabNavigation.styles.tsx (4)
1-5: Consider adding type definition for Colors utility.The Colors utility is imported but its type is not explicitly defined. Consider adding a type definition to improve type safety and documentation.
+// Add to a types file or above the import +type ColorUtility = (theme: Theme) => Record<string, string>; import Colors from "@/constants/Colors";
6-19: Consider using dimension constants for better maintainability.The styles use hardcoded values for dimensions and padding. Consider:
- Using dimension constants for better maintainability
- Ensuring consistent padding values (8 vs 24)
+// Add to a constants file +const SPACING = { + DEFAULT: 8, + LARGE: 24, +}; +const DIMENSIONS = { + TAB_SCROLL_HEIGHT: 68, +}; tabScroll: { - maxHeight: 68, - padding: 8, + maxHeight: DIMENSIONS.TAB_SCROLL_HEIGHT, + padding: SPACING.DEFAULT, paddingTop: 0, }, tabScrollContainer: { - paddingLeft: 8, - paddingRight: 24, + paddingLeft: SPACING.DEFAULT, + paddingRight: SPACING.LARGE, },
20-34: Review positioning and border radius consistency.A few observations about the styles:
position: 'relative'seems unnecessary without any absolutely positioned children- Border radius values are inconsistent (15 for container, 10 for tabs)
+const BORDER_RADIUS = { + LARGE: 15, + MEDIUM: 10, +}; tabContainer: { flexDirection: 'row', gap: 8, paddingHorizontal: 8, paddingVertical: 8, - borderRadius: 15, + borderRadius: BORDER_RADIUS.LARGE, backgroundColor: theme?.dark ? Colors(theme).card : Colors(theme).aliceBlue, - position: 'relative', }, tab: { paddingHorizontal: 24, paddingVertical: 8, justifyContent: 'center', - borderRadius: 10, + borderRadius: BORDER_RADIUS.MEDIUM, },
35-42: Enhance typography consistency and active state visibility.Consider:
- Using typography constants for consistent font sizes and weights
- Adding more visual emphasis to the active state (e.g., font weight)
+const TYPOGRAPHY = { + SIZES: { + REGULAR: 16, + SMALL: 14, + }, + WEIGHTS: { + MEDIUM: '500', + BOLD: '700', + }, +}; tabText: { - fontSize: 16, + fontSize: TYPOGRAPHY.SIZES.REGULAR, color: Colors(theme).primary, - fontWeight: '500', + fontWeight: TYPOGRAPHY.WEIGHTS.MEDIUM, }, activeTabText: { color: Colors(theme).white, + fontWeight: TYPOGRAPHY.WEIGHTS.BOLD, },constants/Colors.ts (1)
28-31: Consider refactoring shared color values.The light theme implementation could be improved:
- Similar to dark theme,
primaryandonSurfaceshare the same value (#054463).- The tag colors are correctly inverted from dark theme, but consider extracting these repeated values into named constants.
Consider refactoring shared values:
+ const TAG_LIGHT = "#f1f3f4"; + const TAG_DARK = "#5f6368"; + const PRIMARY_LIGHT = "#054463"; + const PRIMARY_DARK = "#538BA6"; export default (theme: Theme) => ({ ...(theme.dark ? { - primary: "#538BA6", - onSurface: "#538BA6", - tag: "#5f6368", - tagForeground: "#f1f3f4", + primary: PRIMARY_DARK, + onSurface: PRIMARY_DARK, + tag: TAG_DARK, + tagForeground: TAG_LIGHT, } : { - primary: "#054463", - onSurface: "#054463", - tag: "#f1f3f4", - tagForeground: "#5f6368", + primary: PRIMARY_LIGHT, + onSurface: PRIMARY_LIGHT, + tag: TAG_LIGHT, + tagForeground: TAG_DARK, })components/ui/carousel/carousel.web.tsx (4)
1-7: Consider importing and using proper types for data propsThe component uses
anytype which reduces type safety. Consider defining proper types for the data structure.+import { MediaItem } from '@/types/media'; // Adjust the import path as needed interface CarouselWebProps { - data: any + data: MediaItem[] onImagePress: (uri: string) => void; }
19-20: Improve ref typing and consider cleanupThe video refs could benefit from more specific typing and cleanup on unmount.
- const videoRefs = useRef<{ [key: number]: any }>({}); + const videoRefs = useRef<{ [key: number]: HTMLVideoElement | null }>({}); + + useEffect(() => { + return () => { + // Cleanup video refs on unmount + Object.values(videoRefs.current).forEach(videoRef => { + if (videoRef) { + videoRef.pause(); + } + }); + }; + }, []);
22-26: Remove redundant null checkThe null check for
onImagePressis unnecessary as TypeScript ensures the prop is provided.const handleImagePress = (uri: string) => { - if (onImagePress) { - onImagePress(uri); - } + onImagePress(uri); };
13-57: Consider performance optimizationsA few architectural suggestions:
- Memoize the RenderMediaItem component to prevent unnecessary re-renders
- Consider lazy loading for videos that are not in the current view
- Add swiper callbacks to pause/play videos when sliding
+const MemoizedRenderMediaItem = React.memo(RenderMediaItem); + const CarouselWeb: React.FC<CarouselWebProps> = ({ // ... props }) => { // ... existing code + + const handleIndexChanged = (index: number) => { + // Pause all videos except current + Object.entries(videoRefs.current).forEach(([key, video]) => { + if (video && Number(key) !== index) { + video.pause(); + } + }); + }; + return ( <Swiper // ... existing props + onIndexChanged={handleIndexChanged} > {data.map((item, index) => ( - <RenderMediaItem + <MemoizedRenderMediaItem // ... props /> ))} </Swiper> ); };components/notifications/notification-icon.tsx (1)
Line range hint
3-3: Remove unused importThe
FontAwesomeimport from "@expo/vector-icons" is no longer used after switching toFontAwesomeIcon.-import { FontAwesome } from "@expo/vector-icons";components/ui/empty-state/index.tsx (3)
15-15: Consider using a more specific type for the style propUsing
anytype reduces type safety. Consider usingViewStyleorStyleProp<ViewStyle>from React Native.- style?: any; + style?: StyleProp<ViewStyle>;
44-47: Consider the style spreading orderThe current style spreading order might not allow proper style overrides. Consider moving the base styles last to ensure custom styles take precedence.
style={[ - styles.container, style, + styles.container, ]}
51-56: Consider using typed dimensions for Image componentThe width and height props should be properly typed, and consider making them configurable through props for better reusability.
+type EmptyStateProps = { + imageWidth?: number; + imageHeight?: number; + // ... other props +}; <Image source={imageUrl(image)} - width={256} - height={256} + width={imageWidth ?? 256} + height={imageHeight ?? 256} style={styles.image} />styles/tab1.styles.tsx (1)
16-19: Consider adding JSDoc comments for the styleSince this style is part of what appears to be an onboarding/tutorial UI, consider adding documentation to explain its purpose and expected usage.
+ /** + * Container for the skip button positioned at the top-right corner + * of the onboarding/tutorial screen. + */ skipButtonContainer: { position: "absolute", top: 10, right: 20, },components/drawer-layout/DrawerMenuItem.tsx (2)
Line range hint
27-27: Remove or justify the @ts-ignore commentThe presence of
@ts-ignoresuggests a potential type issue that should be addressed rather than suppressed. Could you investigate why this is needed and either fix the underlying type issue or add a comment explaining why it's necessary?
42-53: Consider simplifying icon stylingThe icon has both a
sizeprop and astylewithwidth. Sincesizealready controls the icon dimensions, the additional width style might be redundant.Consider this simplified version:
<FontAwesomeIcon icon={tab.icon} color={ tab.href.includes(pathname) ? Colors(theme).white : Colors(theme).gray100 } size={28} - style={{ - width: 32, - }} />components/collaboration/CollaborationHeader.tsx (1)
13-63: Optimize component performance with memoizationThe component could benefit from memoization to prevent unnecessary re-renders.
Consider applying these optimizations:
-const CollaborationHeader: React.FC<ColloborationHeaderProps> = ({ +const CollaborationHeader: React.FC<ColloborationHeaderProps> = React.memo(({ collaboration, -}) => { +}) => { const theme = useTheme(); const styles = stylesFn(theme); return ( // ... existing JSX ); -}; +});Also, consider extracting the tags section into a separate memoized component if this component re-renders frequently.
components/ui/brand-switcher/index.tsx (1)
40-43: Remove redundant color stylingThe color is currently defined twice - both in the
colorprop and in thestyleobject. SinceFontAwesomeIconalready handles color through its dedicated prop, the style-based color definition is redundant.<FontAwesomeIcon color={Colors(theme).text} icon={faRightLeft} size={24} style={{ marginLeft: 14, - color: Colors(theme).text, marginBottom: -2, }} />constants/Influencers.ts (2)
Line range hint
1-56: Add TypeScript interfaces for better type safetyThe data structure is complex but lacks type definitions. Consider adding TypeScript interfaces to ensure type safety and better code maintainability.
Add these type definitions at the beginning of the file:
interface Media { type: 'video' | 'image'; uri: string; } interface Influencer { id: string; name: string; handle: string; followers: number; reach: number; rating: string; bio: string; jobsCompleted: number; successRate: string; profilePic: string; collaborationType: 'Paid' | 'Sponsored'; engagement: number; media: Media[]; } export const influencers: Influencer[] = [ // ... existing data ];
Line range hint
1-56: Consider moving sample data to a separate fileThis appears to be sample/mock data in a constants file. Consider:
- Moving this data to a dedicated mock data file (e.g.,
mocks/influencerData.ts)- Using environment variables or configuration files for production data
- Adding a comment indicating this is sample data if it's meant for development
styles/InfluencerCard.styles.tsx (1)
21-33: Consider extracting common spacing valuesThe layout changes look good, but consider extracting common values like padding and gap sizes into theme constants for better maintainability.
+ // In your theme constants file + export const spacing = { + small: 8, + medium: 16, + gap: { + small: 2, + medium: 10 + } + }; content: { - paddingTop: 8, - paddingHorizontal: 16, + paddingTop: spacing.small, + paddingHorizontal: spacing.medium, },styles/collaboration-details/CollaborationDetails.styles.tsx (1)
23-26: LGTM! Consider responsive sizing for different screen sizes.The profile image styling changes look good, with proper spacing and rounded corners that create a card-like appearance.
Consider using responsive sizing for the height to ensure consistent appearance across different device sizes:
- height: 160, + height: '40%', // or use dynamic calculation based on screen heightcomponents/SearchComponent.tsx (2)
42-53: Consider adding press feedback states and accessibility improvementsWhile the Pressable implementation is correct, it could benefit from visual feedback states and accessibility improvements.
Consider this enhancement:
<Pressable onPress={() => { if (ToggleModal) ToggleModal(true); }} style={styles.filterButton} + android_ripple={{ color: 'rgba(255, 255, 255, 0.2)' }} + accessibilityRole="button" + accessibilityLabel="Filter search results" + style={({ pressed }) => [ + styles.filterButton, + pressed && { opacity: 0.8 } + ]} > <FontAwesomeIcon color={Colors(theme).white} icon={faSliders} size={24} /> </Pressable>
69-69: Consider standardizing border radius and padding valuesFor better maintainability and consistency:
- The border radius values differ between searchInput (15) and searchContainer (25)
- The filter button's padding could be simplified
Consider this refinement:
searchInput: { flex: 1, fontSize: 16, - borderRadius: 15, + borderRadius: 25, // Match container radius backgroundColor: Colors(theme).aliceBlue, }, filterButton: { - borderRadius: 15, - paddingVertical: 16, - paddingHorizontal: 18, + borderRadius: 25, // Match container radius + padding: 16, // Simplified padding alignItems: "center",Also applies to: 73-73, 74-74, 75-75
components/notifications/index.tsx (1)
31-36: Minor improvements needed in EmptyState configuration
- Consider moving the image path to a constants file for better maintainability
- Remove the trailing space in the title prop
<EmptyState hideAction - image={require("@/assets/images/illustration2.png")} + image={EMPTY_STATE_IMAGES.NO_NOTIFICATIONS} - title="You are all caught up! " + title="You are all caught up!" subtitle="We have no notifications for you today!" />components/collaboration/create-collaboration/CreateCollaborationMap.tsx (3)
20-22: Consider consolidating map region stateHaving separate state variables for web and native platforms increases complexity. Consider using a single state variable since both platforms use the same structure.
-const [nativeMapRegion, setNativeMapRegion] = useState(mapRegion); -const [webMapRegion, setWebMapRegion] = useState(mapRegion); +const [currentMapRegion, setCurrentMapRegion] = useState(mapRegion);
43-49: Optimize effect dependenciesThe current implementation could cause unnecessary re-renders. Consider moving the platform check outside and watching only the relevant state.
+const mapRegion = Platform.OS === 'web' ? webMapRegion : nativeMapRegion; + useEffect(() => { - if (Platform.OS === 'web') { - onMapLocationChange(webMapRegion); - } else { - onMapLocationChange(nativeMapRegion); - } -}, [nativeMapRegion, webMapRegion]); + onMapLocationChange(mapRegion); +}, [mapRegion]);
16-77: Consider architectural improvementsTo enhance maintainability and performance:
- Extract platform-specific logic into custom hooks
- Memoize the component to prevent unnecessary re-renders
- Consider implementing a map context for deeper component trees
Example implementation:
// hooks/useMapRegion.ts const useMapRegion = (initialRegion: MapRegion) => { const [region, setRegion] = useState(initialRegion); const handleRegionChange = useCallback((newRegion: MapRegion) => { setRegion(newRegion); }, []); return { region, handleRegionChange }; }; // CreateCollaborationMap.tsx const CreateCollaborationMap = memo(({ mapRegion, onMapRegionChange }: CreateCollaborationMapProps) => { const { region, handleRegionChange } = useMapRegion(mapRegion); useEffect(() => { onMapRegionChange(region); }, [region, onMapRegionChange]); return Platform.OS === 'web' ? <WebMap region={region} onChange={handleRegionChange} /> : <NativeMap region={region} onChange={handleRegionChange} />; });components/ui/carousel/render-media-item.tsx (3)
36-60: Add error handling for image loadingConsider adding error handling and loading states for better user experience.
<Image source={imageUrl(item.url || item.uri)} style={[styles.media, { height: height || 250, width: width || "100%" }]} resizeMode="stretch" + onError={(error) => console.error('Image loading error:', error)} + loadingIndicatorSource={require('@/assets/images/placeholder.png')} />
69-75: Consider extracting hardcoded valuesThe fallback video path should be moved to a constants file for better maintainability.
+// In constants/media.ts +export const DEFAULT_VIDEO_PATH = '@/assets/videos/ForBiggerJoyrides.mp4'; -require("@/assets/videos/ForBiggerJoyrides.mp4") +require(DEFAULT_VIDEO_PATH)
83-88: Improve video error handling and playback configurationThe current implementation could benefit from:
- User-facing error handling
- Configurable video playback options
Consider making these properties configurable through props:
+interface RenderMediaItemProps { + // ... existing props + videoConfig?: { + isLooping?: boolean; + shouldPlay?: boolean; + useNativeControls?: boolean; + }; +} <Video // ... existing props - isLooping={false} - shouldPlay={false} - useNativeControls + isLooping={videoConfig?.isLooping ?? false} + shouldPlay={videoConfig?.shouldPlay ?? false} + useNativeControls={videoConfig?.useNativeControls ?? true} onError={(error) => { - console.error("Video Error:", error) + console.error("Video Error:", error); + // Consider adding a callback prop for error handling + onVideoError?.(error); }} />components/ui/carousel/carousel.tsx (5)
25-25: Improve type safety for video refsThe video refs could benefit from a more specific type definition.
- const videoRefs = useRef<{ [key: number]: any }>({}); + const videoRefs = useRef<{ [key: number]: { seek: (time: number) => void } }>({});
43-49: Consider a more concise implementationThe image press handler can be simplified while maintaining the same functionality.
- const handleImagePress = (uri: string) => { - if (!isSwiping) { - if (onImagePress) { - onImagePress(uri); - } - } - }; + const handleImagePress = (uri: string) => { + if (!isSwiping && onImagePress) { + onImagePress(uri); + } + };
56-56: Consider making the carousel height configurableThe hardcoded height of 250 pixels might not be suitable for all use cases.
+interface CarouselProps { + data: CarouselItem[]; + onImagePress?: (data: CarouselItem) => void; + height?: number; +} const CarouselNative: React.FC<CarouselProps> = ({ data, onImagePress, + height = 250, }) => { // ... <Carousel loop width={Dimensions.get("window").width} - height={250} + height={height} // ... />
73-73: Remove unnecessary type annotationsThe map operation doesn't need explicit any types since the types can be inferred.
- {data.map((_: any, index: any) => ( + {data.map((_, index) => (
17-85: Consider performance optimizationsFor better performance, especially with large datasets:
- Memoize the
handleImagePresscallback usinguseCallback- Wrap the
RenderMediaItemcomponent withReact.memo+import { useCallback } from 'react'; const CarouselNative: React.FC<CarouselProps> = ({ // ... }) => { - const handleImagePress = (uri: string) => { + const handleImagePress = useCallback((uri: string) => { if (!isSwiping && onImagePress) { onImagePress(uri); } - }; + }, [isSwiping, onImagePress]); // ... rest of the component }; -export default CarouselNative; +export default React.memo(CarouselNative);🧰 Tools
🪛 Biome (1.9.4)
[error] 36-36: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
components/ui/select/index.tsx (3)
11-16: Consider improving the value prop type definitionThe
valueprop type could be more specific by usingSelectItem[]instead ofSelectItem[] | []since an empty array is already included inSelectItem[].- value: SelectItem[] | []; + value: SelectItem[];
26-42: Optimize selection handler performanceThe current implementation creates multiple array copies. Consider optimizing the multi-select logic:
const handleSelect = (item: SelectItem) => { if (multiselect) { - const index = value.findIndex( - (selectedItem) => selectedItem.value === item.value, - ); - if (index === -1) { - onSelect([...value, item]); - } else { - onSelect([ - ...value.slice(0, index), - ...value.slice(index + 1), - ]); - } + const isSelected = value.some(selectedItem => selectedItem.value === item.value); + onSelect(isSelected + ? value.filter(selectedItem => selectedItem.value !== item.value) + : [...value, item] + ); } else { onSelect([item]); } };
18-23: Enhance accessibility and user experienceConsider adding the following improvements:
- Accessibility props for screen readers
- Loading and error states
- Empty state handling
Example implementation:
interface SelectProps { items: SelectItem[]; multiselect?: boolean; onSelect: (selectedItems: SelectItem[]) => void; value: SelectItem[]; // Add these props isLoading?: boolean; error?: string; placeholder?: string; disabled?: boolean; ariaLabel?: string; }styles/modal/UploadModal.styles.tsx (2)
58-64: Consider refining the iconButton style propertiesThe style definition has a few potential improvements:
- The
colorproperty won't affect the button's background. If this is meant for the icon, it should be moved to a separate icon style.marginHorizontal: 0is redundant as it's the default value.iconButton: { backgroundColor: Colors(theme).primary, borderRadius: 10, - marginHorizontal: 0, - color: Colors(theme).white, padding: 8, }, +iconText: { + color: Colors(theme).white, +},
117-119: Consider extracting common spacing valuesThe spacing values (16, 8) are used multiple times across different styles. Consider extracting these into theme constants for better maintainability.
Example:
// In your theme constants const spacing = { small: 8, medium: 16, } as const; // Then use them in styles gap: spacing.medium, margin: spacing.medium, borderRadius: spacing.small,components/ui/modal/DocumentUploadModal.tsx (2)
92-96: Button implementation follows react-native-paper best practices.The updated Button implementation:
- Uses the recommended children prop pattern instead of title
- Properly implements the Material Design "contained" mode
- Maintains the same functionality
Consider adding a color prop to match your theme:
<Button mode="contained" + color={theme.colors.primary} onPress={() => setVisible(false)} > Cancel </Button>
Line range hint
31-36: Enhance permission denial handling and user messaging.The current permission handling could be more user-friendly and provide clearer guidance.
Consider this improvement:
const openGallery = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { - alert('Media library access is required to select images, videos, or documents'); + Alert.alert( + "Permission Required", + "To upload media, please enable access to your library in your device settings.", + [ + { text: "Cancel", style: "cancel" }, + { text: "Open Settings", onPress: () => Linking.openSettings() } + ] + ); return; }Don't forget to add the necessary imports:
import { Alert, Linking } from 'react-native';components/ui/modal/ImageUploadModal.tsx (2)
103-107: Consider renaming removeImage function to match the Cancel actionThe function name
removeImagedoesn't clearly reflect its usage as a cancel action. This could be confusing for maintainers as the button's label suggests cancellation while the function name suggests image removal.- const removeImage = () => { + const handleCancel = () => { onImageUpload(''); setVisible(false); }; // ... <Button mode="contained" - onPress={removeImage} + onPress={handleCancel} > Cancel </Button>
103-107: Add accessibility props to the Cancel buttonTo improve accessibility for screen readers, consider adding appropriate accessibility props.
<Button mode="contained" onPress={removeImage} + accessibilityLabel="Cancel image upload" + accessibilityHint="Closes the image upload modal without selecting an image" > Cancel </Button>components/collaboration/collaboration-details/OverviewTabContent.tsx (3)
24-36: Move inline styles to stylesFnThe ScrollView contains inline styles that should be moved to the stylesFn for better maintainability and reusability. Also, paddingBottom is defined twice in different style objects.
Consider refactoring to:
// In stylesFn scrollViewContainer: { flex: 1, paddingTop: 8, paddingHorizontal: 16, paddingBottom: 16, }, scrollViewContent: { gap: 16, paddingBottom: 16, }, // In component <ScrollView style={styles.scrollViewContainer} showsVerticalScrollIndicator={false} contentContainerStyle={styles.scrollViewContent} >
54-55: Remove unnecessary string concatenationThe empty string concatenation
{" "}before{collaboration.description}is unnecessary.- <Paragraph style={styles.brandName}> - {" "} - {collaboration.description} - </Paragraph> + <Paragraph style={styles.brandName}> + {collaboration.description} + </Paragraph>
1-106: Add accessibility support and test coverageThe component lacks accessibility attributes and test coverage.
Consider:
- Adding accessibility labels to interactive elements
- Creating a test file (
OverviewTabContent.test.tsx) to cover:
- Rendering with different prop combinations
- Null/undefined handling
- User interactions
- Accessibility features
Would you like me to help generate the test file and accessibility improvements?
app/(public)/pre-signin.tsx (1)
62-73: Add accessibility support and optimize the button implementationWhile the Button upgrade aligns with the theme update, consider these improvements:
- Add accessibility props for better user experience
- Simplify the onPress handler by directly using skipToConnect
Apply this diff:
<Button mode="contained" - onPress={() => { - skipToConnect(); - }} + onPress={skipToConnect} + accessibilityLabel="Skip to connect screen" + accessibilityHint="Navigates to the connection options" > Skip </Button>components/ui/top-tab-navigation/index.tsx (3)
7-14: Enhance type safety and documentation of the interfaceConsider improving the interface definition with better type safety and documentation:
+/** + * Props for the TopTabNavigation component + * @property {Array<{id: string, title: string, component: React.ReactNode}>} tabs - Array of tab configurations + * @property {"compact" | "default"} [size="default"] - Size variant of the tabs + */ interface TopTabNavigationProps { tabs: { id: string; title: string; component: React.ReactNode; }[]; - size?: "compact" | "default"; + size?: 'compact' | 'default'; // Using string literals for better type safety }
27-29: Consider preserving active tab state across tab updatesThe current implementation resets to the first tab whenever tabs change, which might disrupt user experience. Consider preserving the active tab if it still exists in the new tabs array:
useEffect(() => { - setActiveTab(tabs[0]); + const currentTabStillExists = tabs.find(tab => tab.id === activeTab.id); + setActiveTab(currentTabStillExists || tabs[0]); }, [tabs]);
31-45: Simplify renderTabContent functionThe current implementation can be simplified by removing unnecessary complexity:
const renderTabContent = () => ( <View style={[styles.tabContent]}> - {(() => { - let content - content = activeTab.component; - return content; - })()} + {activeTab.component} </View> );components/collaboration/CollaborationCard.tsx (2)
76-84: Consider adding accessibility labels to TagsWhile the Tag implementation looks cleaner, consider enhancing accessibility for screen readers.
Add accessibility props to the Tags:
- <Tag> + <Tag accessibilityLabel={`${props.applications} applications`}> Applied: {props.applications} </Tag> - <Tag> + <Tag accessibilityLabel={`${props.invitations} invitations`}> Invited: {props.invitations} </Tag> - <Tag> + <Tag accessibilityLabel={`${props.acceptedApplications} shortlisted`}> Shortlisted: {props.acceptedApplications} </Tag>
Line range hint
27-27: Consider renaming JobCard to CollaborationCard for consistencyThe component name
JobCarddoesn't match the file nameCollaborationCard.tsx. This could lead to confusion. Consider renaming for better maintainability.-const JobCard = (props: CollaborationAdCardProps) => { +const CollaborationCard = (props: CollaborationAdCardProps) => { -export default JobCard; +export default CollaborationCard;components/collaboration/collaboration-details/ApplicationsTabContent.tsx (5)
15-15: Consider adding proper TypeScript interface for props.Using
anytype reduces type safety. Consider creating a proper interface for the component props.-const ApplicationsTabContent = (props: any) => { +interface ApplicationsTabContentProps { + pageID: string; + collaboration: any; // TODO: Define proper type +} + +const ApplicationsTabContent = (props: ApplicationsTabContentProps) => {
77-85: Consider moving the image path to constants.The empty state implementation looks good, but consider moving the image path to a constants file for better maintainability.
+// In constants/images.ts +export const ILLUSTRATIONS = { + NO_APPLICATIONS: require("@/assets/images/illustration6.png") +}; // In component - image={require("@/assets/images/illustration6.png")} + image={ILLUSTRATIONS.NO_APPLICATIONS}
Line range hint
95-107: Remove hardcoded values in influencer data.Several properties appear to use hardcoded values which could be misleading:
- Default handle "@handle"
- Hardcoded bio "I am a content creator"
- Static jobsCompleted and successRate values
id: item.id, profilePic: item.profileImage, name: item.name, - handle: item.handle || "@handle", + handle: item.handle || `@${item.name?.toLowerCase().replace(/\s+/g, '')}`, media: item.attachments, followers: item.backend ? item.backend.followers : 1000, reach: item.backend ? item.backend.reach : 10000, rating: item.backend ? item.backend.rating : 4.5, - bio: "I am a content creator", + bio: item.bio || '', - jobsCompleted: 12, - successRate: 100, + jobsCompleted: item.jobsCompleted || 0, + successRate: item.successRate || 0,
121-130: Consider extracting styles and separator component.The ItemSeparatorComponent and its styles could be extracted for better code organization and reusability.
+const ListSeparator = () => { + const theme = useTheme(); + return ( + <View + style={[ + styles.separator, + { + backgroundColor: theme.dark ? Colors(theme).background : Colors(theme).aliceBlue, + } + ]} + /> + ); +}; + +const styles = StyleSheet.create({ + separator: { + height: 16, + }, +}); // In FlatList - ItemSeparatorComponent={() => (...)} + ItemSeparatorComponent={ListSeparator}
132-146: Simplify BottomSheetActions rendering and improve props handling.The current implementation could be simplified and made more type-safe.
- { - isVisible && ( - <BottomSheetActions - cardType="applicationCard" - data={{ - collaboration: props.collaboration - }} - isVisible={isVisible} - onClose={() => setIsVisible(false)} - snapPointsRange={["30%", "50%"]} - cardId={selectedApplication} - key={selectedApplication?.applicationID} - /> - ) - } + <BottomSheetActions + cardType="applicationCard" + data={{ collaboration: props.collaboration }} + isVisible={isVisible} + onClose={() => setIsVisible(false)} + snapPointsRange={["30%", "50%"]} + cardId={selectedApplication} + key={selectedApplication?.applicationID} + />app/(main)/(drawer)/(tabs)/_layout.tsx (2)
52-56: Maintain consistent icon sizes across tabs.The Explore Influencers tab uses a 28px icon while other tabs use 24px. This inconsistency might affect visual harmony.
- size={28} + size={24}
Line range hint
64-73: Remove redundant color style.The color is defined twice for the drawer toggle icon - both in the color prop and in the style object.
color={Colors(theme).text} icon={faRightLeft} size={24} style={{ marginLeft: 14, - color: Colors(theme).text, marginBottom: -2, }}components/explore-influencers/index.tsx (3)
76-85: LGTM: Well-implemented separator with theme supportThe separator implementation correctly uses theme context and maintains consistent spacing. Consider adding type safety for the theme parameter.
-backgroundColor: theme.dark ? Colors(theme).background : Colors(theme).aliceBlue, +backgroundColor: theme.dark ? Colors(theme as Theme).background : Colors(theme as Theme).aliceBlue,
87-96: LGTM: Improved layout consistencyThe SearchComponent wrapper improves layout consistency. Consider extracting the padding value 16 to a constant since it's used in multiple places.
+const SPACING = 16; + const ExploreInfluencers = () => { // ... existing code ... return ( <AppLayout> <FlatList // ... other props ... contentContainerStyle={{ - paddingTop: 16, - paddingBottom: 16, + paddingTop: SPACING, + paddingBottom: SPACING, }} ItemSeparatorComponent={() => ( <View style={{ - height: 16, + height: SPACING, backgroundColor: theme.dark ? Colors(theme).background : Colors(theme).aliceBlue, }} /> )} ListHeaderComponent={ <View style={{ - paddingHorizontal: 16, + paddingHorizontal: SPACING, }} > <SearchComponent // ... props ... /> </View> } /> </AppLayout> ); };
Line range hint
33-35: Clean up or document commented influencer type filteringThere's commented code for
isInfluencerTypeMatch. If this feature is planned for future implementation, consider adding a TODO comment with the ticket reference. If it's no longer needed, consider removing it.components/drawer-layout/DrawerMenuContent.tsx (4)
11-11: Consider virtualizing the scroll view for better performanceThe switch to
ScrollViewmight impact performance with large lists. Consider usingFlatListorVirtualizedListinstead, especially for the brands list view, as these components implement windowing and recycling of list items.-import { Platform, ScrollView } from "react-native"; +import { Platform, FlatList } from "react-native"; - <ScrollView - style={{ - flex: 1, - gap: 6, - }} - > + <FlatList + style={{ + flex: 1, + }} + contentContainerStyle={{ + gap: 6 + }} + data={xl ? DRAWER_MENU_CONTENT_ITEMS : filteredBrands} + renderItem={({ item }) => xl ? ( + <DrawerMenuItem tab={item} /> + ) : ( + <BrandItem + active={selectedBrand?.id === item.id} + image={item.image} + key={item.id.toString()} + menu={true} + onPress={() => handleBrandChange(item)} + showImage={true} + title={item.name} + /> + )} + keyExtractor={(item) => xl ? item.href : item.id.toString()} + >Also applies to: 126-131
Line range hint
156-158: Fix Platform.OS condition in marginBottom styleThe Platform.OS check in the marginBottom calculation has a potential syntax error that could lead to unexpected behavior.
- marginBottom: bottom + Platform.OS === 'android' ? 24 : 44, + marginBottom: bottom + (Platform.OS === 'android' ? 24 : 44),
Line range hint
77-86: Consider debouncing the search functionalityThe current implementation updates the filtered results on every keystroke, which might cause performance issues with large lists.
Consider using a debounce utility:
import { useMemo } from 'react'; import debounce from 'lodash/debounce'; // Inside component const debouncedSearch = useMemo( () => debounce((text: string) => { if (!text) { setFilteredBrands(brands); return; } setFilteredBrands(brands.filter(brand => brand.name.toLowerCase().includes(text.toLowerCase()) )); }, 300), [brands] ); const handleSearchChange = (text: string) => { setSearch(text); debouncedSearch(text); };🧰 Tools
🪛 Biome (1.9.4)
[error] 25-26: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
91-92: Consider extracting magic numbers into theme constantsThe hardcoded padding and font size values should be moved to a theme configuration for better maintainability and consistency.
+ // In your theme file + export const spacing = { + headerPaddingTop: { + web: 12, + native: 64 + }, + contentPadding: 24, + }; + export const typography = { + headerSize: 24, + }; - paddingTop: Platform.OS === 'web' ? 12 : 64, + paddingTop: spacing.headerPaddingTop[Platform.OS === 'web' ? 'web' : 'native'], - paddingHorizontal: 24, - fontSize: 24, + paddingHorizontal: spacing.contentPadding, + fontSize: typography.headerSize,Also applies to: 98-102
app/(onboarding)/onboarding-get-started.tsx (2)
75-75: Enhance error handling with user feedbackWhile using
console.erroris better thanconsole.log, consider adding:
- User-friendly error messages
- Error tracking/monitoring
- console.error(error); + console.error('Failed to submit onboarding survey:', error); + // Show error message to user + showErrorMessage('Something went wrong. Please try again.'); + // Optional: Track error for monitoring + errorTracker.capture(error);
Line range hint
41-77: Consider adding form validation and state managementThe survey submission logic could benefit from:
- Form validation before submission (all fields required?)
- Loading states during submission
- Proper state management for the survey data
Consider implementing form validation:
const isFormValid = () => { return hearAboutUs && useFor && volumeOfCollaboration; }; const handleSubmit = async () => { if (!isFormValid()) { showErrorMessage('Please fill in all fields'); return; } // ... rest of the submission logic };components/proposals/Invitations.tsx (3)
134-140: Fix typo in EmptyState subtitleThere's a typo in the subtitle text: "woudl" should be "would".
- subtitle="Start building your profile today to have better reach. If any brand invites you to collaborate we woudl show it here" + subtitle="Start building your profile today to have better reach. If any brand invites you to collaborate we would show it here"
193-203: Consider using dynamic snap pointsThe snap points are currently hardcoded to ["20%", "50%"]. Consider making these dynamic based on screen size or content height for better adaptability across different devices.
- snapPointsRange={["20%", "50%"]} + snapPointsRange={[ + Math.min(screenHeight * 0.2, contentHeight), + Math.min(screenHeight * 0.5, contentHeight) + ]}
Line range hint
46-84: Enhance error handling with user feedbackThe current error handling only logs to console. Consider adding user feedback for error states.
} catch (error) { console.error("Error fetching proposals: ", error); + // Show error feedback to user + setError("Failed to fetch proposals. Please try again."); } finally { setIsLoading(false); }components/proposals/Applications.tsx (2)
Line range hint
25-27: Consider co-locating the bottom sheet state.The
selectedCollabIdstate is only used by the BottomSheetActions component. Consider moving this state and its handlers into a separate bottom sheet component to improve code organization and reduce the main component's complexity.- const [isVisible, setIsVisible] = useState(false); - const [selectedCollabId, setSelectedCollabId] = useState<string | null>(null); + const BottomSheetWrapper = ({ children }) => { + const [isVisible, setIsVisible] = useState(false); + const [selectedCollabId, setSelectedCollabId] = useState<string | null>(null); + + const openBottomSheet = (id: string) => { + setIsVisible(true); + setSelectedCollabId(id); + }; + const closeBottomSheet = () => setIsVisible(false); + + return ( + <> + {children(openBottomSheet)} + {isVisible && ( + <BottomSheetActions + cardId={selectedCollabId || ""} + cardType="activeCollab" + isVisible={isVisible} + onClose={closeBottomSheet} + snapPointsRange={["20%", "50%"]} + key={selectedCollabId} + /> + )} + </> + ); + };
Line range hint
44-102: Consider optimizing the data fetching strategy.The current implementation makes multiple nested Firestore queries for each collaboration, which could lead to performance issues with larger datasets. Consider:
- Using composite queries to fetch related data
- Implementing pagination
- Caching frequently accessed data
Here's a suggested approach using batch operations:
const fetchProposals = async () => { if (!selectedBrand) return; try { // 1. Fetch collaborations with pagination const BATCH_SIZE = 10; const collaborationQuery = query( collection(FirestoreDB, "collaborations"), where("brandId", "==", selectedBrand?.id), orderBy("timeStamp", "desc"), limit(BATCH_SIZE) ); // 2. Use batched reads for applications and invitations const fetchRelatedData = async (collabId: string) => { const batch = FirestoreDB.batch(); const appRef = collection(FirestoreDB, "collaborations", collabId, "applications"); const invRef = collection(FirestoreDB, "collaborations", collabId, "invitations"); return Promise.all([ getDocs(query(appRef, limit(100))), getDocs(query(invRef, limit(100))) ]); }; // 3. Process in smaller batches const processCollaborations = async (snapshot: QuerySnapshot) => { const batchPromises = snapshot.docs.map(async (doc) => { const [appSnapshot, invSnapshot] = await fetchRelatedData(doc.id); return { ...doc.data(), id: doc.id, applications: appSnapshot.size, invitations: invSnapshot.size, acceptedApplications: appSnapshot.docs.filter( d => d.data().status === "accepted" ).length }; }); return Promise.all(batchPromises); }; const snapshot = await getDocs(collaborationQuery); const proposals = await processCollaborations(snapshot); setProposals(proposals); } catch (error) { console.error("Error fetching proposals: ", error); } finally { setIsLoading(false); } };app/(onboarding)/onboarding-your-brand.tsx (1)
163-163: Consider moving inline styles to the styles object.While the implementation is correct, the inline backgroundColor style in the Pressable component could be moved to the styles object for better maintainability and reusability.
// In the styles object + pressableItem: { + backgroundColor: Colors(theme).background, + }, // In the component - style={{ - backgroundColor: Colors(theme).background, - }} + style={styles.pressableItem}Also applies to: 168-179
components/BottomSheetActions.tsx (4)
103-103: Enhance error handling with proper error types and detailed messagesWhile changing to
console.erroris good, consider these improvements:
- Add proper error typing
- Include specific error details in toast messages
- Implement error tracking
- console.error(error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + console.error('Operation failed:', errorMessage); + // Consider adding error tracking here + Toaster.error(`Failed to complete operation: ${errorMessage}`);Also applies to: 125-125, 141-141
Line range hint
13-19: Improve type safety by removing 'any' types and @ts-ignore commentsThe component has several type safety issues that should be addressed:
- The
dataprop needs proper typing- @ts-ignore comments should be replaced with proper type assertions
Consider defining proper interfaces:
interface CollaborationData { collaboration: { id: string; name: string; }; } interface CardIds { collaborationID: string; applicationID: string; influencerID: string; } interface BottomSheetActionsProps { cardType: 'influencerType' | 'promotionType' | 'influencerCard' | 'applicationCard' | 'invitationCard' | 'activeCollab'; data?: CollaborationData; cardId?: CardIds; isVisible: boolean; snapPointsRange: [string, string]; onClose: () => void; }
174-174: Consolidate repeated padding stylesThe
paddingBottom: 28style is repeated across multiple List.Section components. Consider extracting this to a shared style.const styles = StyleSheet.create({ // ... existing styles ... + listSection: { + paddingBottom: 28, + }, }); - <List.Section style={{ paddingBottom: 28 }}> + <List.Section style={styles.listSection}>Also applies to: 198-198, 222-222, 245-245
Line range hint
1-313: Consider breaking down the component and extracting logicThe component handles multiple responsibilities and could benefit from some architectural improvements:
- Extract card-specific components to reduce the switch statement complexity
- Move async operations to custom hooks
- Add loading states for async operations
Consider this structure:
// hooks/useCollaborationActions.ts export const useCollaborationActions = () => { const handleAcceptApplication = async () => { /* ... */ }; const handleRejectApplication = async () => { /* ... */ }; const delistCollaboration = async () => { /* ... */ }; return { handleAcceptApplication, handleRejectApplication, delistCollaboration }; }; // components/CardContents/InfluencerCardContent.tsx export const InfluencerCardContent = ({ onClose }) => ( <List.Section style={styles.listSection}> {/* ... */} </List.Section> ); // Similar components for other card typescomponents/FilterModal.tsx (1)
164-166: Consider extracting repeated slider stylesThe selectedStyle configuration is duplicated across three MultiSlider components. Consider extracting it to a constant or style object for better maintainability.
+ const sliderSelectedStyle = { + backgroundColor: Colors(theme).primary, + }; - selectedStyle={{ - backgroundColor: Colors(theme).primary, - }} + selectedStyle={sliderSelectedStyle}Also applies to: 189-191, 216-218
hooks/request/use-influencers.tsx (4)
12-12: Specify the type ofinfluencersstate for better type safetyCurrently,
influencersis typed asany[], which bypasses the benefits of TypeScript's static type checking. Defining a specific interface for your influencer data will enhance type safety and reduce potential runtime errors.Example:
+interface Influencer { + id: string; + name: string; + // Add other influencer properties here +} -const [influencers, setInfluencers] = useState<any[]>([]); +const [influencers, setInfluencers] = useState<Influencer[]>([]);
103-103: Simplify the cleanup function using optional chainingInstead of
unsubscribe && unsubscribe(), you can use optional chainingunsubscribe?.()for a cleaner and more concise syntax.Apply this diff:
-return () => unsubscribe && unsubscribe(); +return () => unsubscribe?.();🧰 Tools
🪛 Biome (1.9.4)
[error] 103-103: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
83-99: Add error handling incheckIfAlreadyInvitedThe
checkIfAlreadyInvitedfunction performs asynchronous operations but lacks error handling. Incorporating atry-catchblock will help manage potential errors during thegetDocscall.Apply this diff:
const checkIfAlreadyInvited = async (influencerID: string) => { + try { const invitationsRef = collection( FirestoreDB, "collaborations", pageID, "invitations" ); const influencersQuery = query( invitationsRef, where("userId", "==", influencerID) ); const invitedInfluencer = await getDocs(influencersQuery); return invitedInfluencer.docs.length > 0; + } catch (error) { + console.error("Error checking if influencer is already invited:", error); + return false; + } };
20-48: Assess the necessity of real-time updates infetchInitialInfluencersThe
fetchInitialInfluencersfunction usesonSnapshotto set up a real-time listener. If real-time updates are not required for the initial influencers list, consider usinggetDocsto fetch data once. This change can reduce resource consumption and simplify the data fetching logic.components/collaboration/collaboration-details/index.tsx (4)
63-65: Utilize the collaboration logo if availableThe
logoprop is currently commented out and an empty string is passed. If the logo is available in thecollaborationdata, you should use it to enhance the user interface.Update the
OverviewTabContentcomponent props:collaboration={collaboration as Collaboration} - // logo={collaboration?.logo} - logo={""} + logo={collaboration?.logo || ""}
74-79: Ensurecollaborationobject passed toApplicationsTabContentis completeYou're currently passing an object with
idandnameproperties. Ifcollaboration.nameis undefined,namewill beundefined. It might be better to ensure that all necessary properties are provided or handle undefined values within theApplicationsTabContentcomponent.Consider passing the entire
collaborationobject if needed:pageID={pageID} - collaboration={{ - id: pageID, - name: collaboration?.name, - }} + collaboration={collaboration as Collaboration}
35-35: Remove unnecessary type assertion forpageIDSince
pageIDis already typed as astringinCollaborationDetailsProps, the type assertionas stringis redundant.Simplify the
doccalls:- const collabRef = doc(FirestoreDB, "collaborations", pageID as string); + const collabRef = doc(FirestoreDB, "collaborations", pageID); ... - const brandRef = doc(FirestoreDB, "brands", data.brandId); + const brandRef = doc(FirestoreDB, "brands", data.brandId);
100-102: IncludefetchCollaborationin theuseEffectdependency array or define it insideThe
useEffecthook depends onfetchCollaboration, which is defined outside the hook. To prevent potential stale closures or linting warnings, includefetchCollaborationin the dependency array or define it within theuseEffect.Option 1: Include
fetchCollaborationin dependencies:useEffect(() => { fetchCollaboration(); - }, [pageID]); + }, [pageID, fetchCollaboration]);Option 2: Define
fetchCollaborationinside theuseEffect:- const fetchCollaboration = async () => { + useEffect(() => { + const fetchCollaboration = async () => { // ... existing code ... }; fetchCollaboration(); - }, [pageID]); + }, [pageID]);components/collaboration/collaboration-details/InvitationsTabContent.tsx (3)
Line range hint
47-72: Use consistentasync/awaitsyntax and improve error handlingMixing
async/awaitwith.then()can reduce code readability. It's recommended to useasync/awaitconsistently for better error handling and clarity.Apply this diff to refactor the code:
setIsInviting(true); - await addDoc(invitationRef, invitationPayload).then(() => { - setIsMessageModalVisible(false); - Toaster.success("Invitation sent successfully"); - }); + await addDoc(invitationRef, invitationPayload); + setIsMessageModalVisible(false); + Toaster.success("Invitation sent successfully");Consider improving the error message to include the error details:
} catch (error) { console.error(error); - Toaster.error("Failed to send invitation"); + Toaster.error(`Failed to send invitation: ${error.message}`); } finally { setMessage(""); setIsInviting(false); }
106-107: Avoid clearinginfluencersstate before fetchingClearing the
influencersstate withsetInfluencers([]);before fetching new data may cause unnecessary UI updates or flicker. LetfetchInitialInfluencers()handle updating the state.Apply this diff to remove the unnecessary state clearing:
onRefresh={() => { - setInfluencers([]); fetchInitialInfluencers(); }}
25-25: Specify prop types forInvitationsTabContentcomponentCurrently,
propsis typed asany. Defining proper prop types enhances code maintainability and type safety.Consider defining an interface for
props:interface InvitationsTabContentProps { pageID: string; // Add other prop definitions here } const InvitationsTabContent = (props: InvitationsTabContentProps) => { // ... };components/InfluencerCard.tsx (3)
207-212: Add user interaction to the message iconThe message icon currently does not respond to user interactions. If the intent is to allow users to send messages or initiate chats with the influencer, consider wrapping the icon with a
TouchableOpacityand adding anonPresshandler.Apply this diff:
<View style={styles.statItem}> + <TouchableOpacity onPress={() => { + // Implement message functionality + if (props.ToggleMessageModal) { + props.ToggleMessageModal(); + } + }}> <FontAwesomeIcon icon={faMessage} color={Colors(theme).primary} size={18} /> + </TouchableOpacity> </View>
173-205: Improve accessibility by adding descriptive labels to iconsFor better accessibility, consider adding
accessibilityLabelandaccessibleprops to the icons so that screen readers can provide meaningful descriptions.Apply this diff:
<FontAwesomeIcon icon={faUsers} color={Colors(theme).primary} size={20} + accessible={true} + accessibilityLabel="Followers" />Repeat for other icons like
faBullseyeandfaStar, providing appropriate labels like "Reach" and "Rating".
215-219: Enhance the bio expansion for better user experienceCurrently, tapping on the bio text toggles the expansion. However, if the bio text is short, tapping might not change anything. Consider adding a "Read more" or "Show less" link to indicate that the text can be expanded or collapsed.
Apply this diff:
<TouchableOpacity onPress={() => setBioExpanded(!bioExpanded)}> <Text numberOfLines={bioExpanded ? undefined : 2} style={styles.bio}> {influencer.bio} + {!bioExpanded && influencer.bio.length > 100 ? ( + <Text style={styles.readMore}> Read more</Text> + ) : bioExpanded ? ( + <Text style={styles.readLess}> Show less</Text> + ) : null} </Text> </TouchableOpacity>You may need to adjust the character limit and style accordingly.
app/(modal)/create-collaboration.tsx (4)
Line range hint
291-303: Validation May Not Detect Empty SelectionsIn the validation before moving to the next screen, you're checking if
promotionType,collabType, andplatformare truthy. Since empty arrays are truthy in JavaScript, this check won't detect if the user hasn't made a selection.Update the validation to check the length of these arrays:
if ( !collaborationName || !aboutCollab || !budgetMin || !budgetMax || !numInfluencers || - !promotionType || - !collabType || - !platform + promotionType.length === 0 || + collabType.length === 0 || + platform.length === 0 ) { Toaster.error("Please fill all fields"); return; }
346-366: Consider Using 'Select' Component for Location SelectionFor consistency with the rest of the form, consider replacing the
RadioButton.Groupfor theLocationfield with theSelectcomponent.This will provide a uniform user experience and maintain consistency across the form inputs.
-<RadioButton.Group - onValueChange={(newValue) => setLocation(newValue)} - value={location} -> - <RadioButton.Item label="Remote" value="Remote" ... /> - <RadioButton.Item label="Physical" value="Physical" ... /> -</RadioButton.Group> +<Select + items={[ + { label: "Remote", value: "Remote" }, + { label: "Physical", value: "Physical" }, + ]} + onSelect={(selectedItems) => setLocation(selectedItems[0].value)} + value={[{ label: location, value: location }]} +/>
131-131: Address the TODO Comment for Location NameThere's a TODO comment indicating that the location name should be added using a geocoding API:
// TODO: Add location name using geocoding APIWould you like assistance in implementing the geocoding API to retrieve the location name based on the selected coordinates? I can help integrate a geocoding service like Google Maps API or OpenStreetMap.
388-393: Enhance Link Management with Edit and Delete OptionsCurrently, the added links are displayed as plain text without options to edit or remove them:
links.map((link, index) => ( <Paragraph key={index}> {link.name}: {link.url} </Paragraph> ))Consider enhancing the user experience by displaying the links in a list with options to edit or delete individual links. This will provide users with more control over the links they include.
Example implementation:
links.map((link, index) => ( <View key={index} style={styles.linkItem}> <Paragraph>{link.name}: {link.url}</Paragraph> <IconButton icon="pencil" onPress={() => handleEditLink(index)} /> <IconButton icon="delete" onPress={() => handleDeleteLink(index)} /> </View> ))You'll need to implement
handleEditLinkandhandleDeleteLinkfunctions to manage link editing and deletion.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (7)
assets/images/illustration1.pngis excluded by!**/*.pngassets/images/illustration2.pngis excluded by!**/*.pngassets/images/illustration3.pngis excluded by!**/*.pngassets/images/illustration4.pngis excluded by!**/*.pngassets/images/illustration5.pngis excluded by!**/*.pngassets/images/illustration6.pngis excluded by!**/*.pngpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (77)
app/(auth)/create-new-account.tsx(1 hunks)app/(auth)/forget-password.tsx(0 hunks)app/(auth)/login.tsx(0 hunks)app/(main)/(drawer)/(tabs)/_layout.tsx(6 hunks)app/(main)/(screens)/CollaborationHistory.tsx(1 hunks)app/(main)/(screens)/_layout.tsx(0 hunks)app/(main)/(screens)/collaboration-details/[pageID].tsx(1 hunks)app/(main)/_layout.tsx(0 hunks)app/(modal)/create-collaboration.tsx(8 hunks)app/(modal)/create-collaboration.web.tsx(0 hunks)app/(onboarding)/onboarding-brand-preference.tsx(1 hunks)app/(onboarding)/onboarding-get-started.tsx(4 hunks)app/(onboarding)/onboarding-your-brand.tsx(5 hunks)app/(public)/pre-signin.tsx(2 hunks)components/BottomSheetActions.tsx(7 hunks)components/FilterModal.tsx(6 hunks)components/InfluencerCard.tsx(5 hunks)components/SearchComponent.tsx(3 hunks)components/channel/channel-list.tsx(1 hunks)components/collaboration/CollaborationCard.tsx(3 hunks)components/collaboration/CollaborationDetails.tsx(0 hunks)components/collaboration/CollaborationHeader.tsx(1 hunks)components/collaboration/collaboration-details/ApplicationsTabContent.tsx(4 hunks)components/collaboration/collaboration-details/InvitationsTabContent.tsx(5 hunks)components/collaboration/collaboration-details/OverviewTabContent.tsx(1 hunks)components/collaboration/collaboration-details/SettingsTabContent.tsx(1 hunks)components/collaboration/collaboration-details/index.tsx(1 hunks)components/collaboration/create-collaboration/CreateCollaborationMap.tsx(1 hunks)components/collaborations/index.tsx(1 hunks)components/contracts/index.tsx(1 hunks)components/drawer-layout/BrandItem.tsx(2 hunks)components/drawer-layout/DrawerMenuContent.tsx(2 hunks)components/drawer-layout/DrawerMenuItem.tsx(2 hunks)components/explore-influencers/index.tsx(3 hunks)components/notifications/index.tsx(2 hunks)components/notifications/notification-icon.tsx(2 hunks)components/proposals/Applications.tsx(3 hunks)components/proposals/Invitations.tsx(2 hunks)components/ui/brand-switcher/index.tsx(2 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)components/ui/empty-state/index.tsx(2 hunks)components/ui/menu-icon/index.tsx(2 hunks)components/ui/modal/DocumentUploadModal.tsx(2 hunks)components/ui/modal/ImageUploadModal.tsx(2 hunks)components/ui/select/index.tsx(1 hunks)components/ui/tag/index.tsx(1 hunks)components/ui/top-tab-navigation/index.tsx(1 hunks)constants/Colors.ts(3 hunks)constants/CreateCollaborationForm.ts(1 hunks)constants/Influencers.ts(2 hunks)constants/Themes/Theme.ts(1 hunks)hooks/request/index.ts(1 hunks)hooks/request/use-influencers.tsx(1 hunks)layouts/app-layout/index.tsx(2 hunks)package.json(2 hunks)styles/CollaborationCard.styles.tsx(3 hunks)styles/FilterModal.styles.tsx(1 hunks)styles/InfluencerCard.styles.tsx(3 hunks)styles/NotificationCard.styles.tsx(1 hunks)styles/Proposal.styles.tsx(2 hunks)styles/brand-item/BrandItem.styles.tsx(1 hunks)styles/collaboration-details/CollaborationDetails.styles.tsx(4 hunks)styles/collaboration-details/CollaborationHeader.styles.tsx(1 hunks)styles/empty-state/EmptyState.styles.tsx(2 hunks)styles/forget-password.styles.tsx(0 hunks)styles/login.styles.tsx(0 hunks)styles/modal/UploadModal.styles.tsx(2 hunks)styles/onboarding/brand.styles.tsx(1 hunks)styles/onboarding/preference.styles.tsx(0 hunks)styles/signup.styles.tsx(0 hunks)styles/tab1.styles.tsx(1 hunks)styles/tag/Tag.styles.tsx(1 hunks)styles/top-tab-navigation/TopTabNavigation.styles.tsx(1 hunks)utils/conversion.ts(1 hunks)utils/url.ts(1 hunks)
💤 Files with no reviewable changes (10)
- app/(auth)/forget-password.tsx
- app/(auth)/login.tsx
- app/(main)/(screens)/_layout.tsx
- app/(main)/_layout.tsx
- app/(modal)/create-collaboration.web.tsx
- components/collaboration/CollaborationDetails.tsx
- styles/forget-password.styles.tsx
- styles/login.styles.tsx
- styles/onboarding/preference.styles.tsx
- styles/signup.styles.tsx
✅ Files skipped from review due to trivial changes (3)
- components/collaboration/collaboration-details/SettingsTabContent.tsx
- constants/CreateCollaborationForm.ts
- hooks/request/index.ts
🧰 Additional context used
🪛 Biome (1.9.4)
components/collaboration/create-collaboration/CreateCollaborationMap.tsx
[error] 6-6: Do not shadow the global "Map" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
components/drawer-layout/DrawerMenuContent.tsx
[error] 25-26: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
components/ui/carousel/carousel.tsx
[error] 36-36: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
components/ui/select/index.tsx
[error] 55-57: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
hooks/request/use-influencers.tsx
[error] 103-103: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (90)
utils/conversion.ts (1)
1-6: Verify consistent usage across components
Let's ensure the function is implemented consistently across all components that display numerical data.
✅ Verification successful
Function usage is consistent across the codebase
The verification shows that convertToKUnits is only used in InfluencerCard component for formatting followers and reach counts. The search for other number formatting patterns (toFixed with k/K/m/M/b/B units) only found the implementation within the utility function itself, confirming there are no inconsistent number formatting patterns elsewhere in the codebase.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Find all usage of convertToKUnits to verify consistent implementation
# Search for direct usage of convertToKUnits
echo "Direct function usage:"
rg -A 2 "convertToKUnits"
# Search for potential places where it could be used (number formatting patterns)
echo "\nPotential places where convertToKUnits could be used:"
rg -A 2 "toFixed\(.*\).*[kKmMbB]"
Length of output: 1260
app/(main)/(screens)/CollaborationHistory.tsx (1)
1-13: Review component placement in the application structure
The AI summary mentions related changes in app/(modal)/create-collaboration.tsx. Given this component's current location in (main)/(screens), please verify:
- Should this component be in the modal directory instead?
- Are there duplicate implementations across different directories?
- What's the intended navigation flow between these components?
Let's analyze the application structure:
✅ Verification successful
Component placement is correct in the current directory structure
Based on the analysis:
- The
CollaborationHistorycomponent in(main)/(screens)is correctly placed as it's a full screen view, whilecreate-collaboration.tsxin(modal)is a modal component. - These are distinct components with different purposes:
create-collaboration.tsxis a modal form for creating new collaborationsCollaborationHistoryis a main screen for viewing collaboration history
- The navigation flow is clear:
- Modal can be dismissed to return to main screens
- Main screens are accessed through normal navigation
- Both serve different user interactions
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for potential duplicate implementations
echo "Checking for collaboration-related files in modal directory..."
fd "collaboration" "app/(modal)"
echo "\nAnalyzing imports of this component..."
rg -l "CollaborationHistory" --type tsx
Length of output: 363
Script:
#!/bin/bash
# Let's try a more comprehensive analysis with ripgrep without file type filter
echo "Analyzing imports and usage of CollaborationHistory..."
rg "CollaborationHistory"
echo "\nChecking the structure and content of both files..."
echo "\nContent of create-collaboration.tsx:"
cat "app/(modal)/create-collaboration.tsx"
echo "\nChecking navigation patterns..."
rg "router.push|href.*collaboration" -A 2
Length of output: 18259
styles/tag/Tag.styles.tsx (1)
7-11: 🛠️ Refactor suggestion
Verify the padding values and consider adding text overflow handling
The zero padding (paddingVertical: 0, paddingHorizontal: 0) seems unusual for a tag component and might affect its appearance and usability. Additionally, consider handling text overflow scenarios.
Consider applying these improvements:
tag: {
backgroundColor: Colors(theme).tag,
- paddingVertical: 0,
- paddingHorizontal: 0,
+ paddingVertical: 4,
+ paddingHorizontal: 8,
borderRadius: 10,
+ overflow: 'hidden',
},components/ui/tag/index.tsx (2)
1-3: LGTM: Clean imports with clear dependencies
The imports are well-organized and properly scoped. The component relies on standard React Native navigation theming and react-native-paper components.
9-10: Verify theme integration across the application
The component uses the navigation theme, which is good for consistency. However, we should verify that the imported styles properly handle all theme modes (light/dark).
✅ Verification successful
Theme integration is properly implemented
The Tag component correctly handles both light and dark themes:
- Background colors:
#5f6368(light) /#f1f3f4(dark) - Text colors:
#f1f3f4(light) /#5f6368(dark)
The colors are appropriately inverted between themes to maintain contrast and readability in both modes.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if the imported styles handle both theme modes
ast-grep --pattern 'export const stylesFn = ({ colors, dark }) => StyleSheet.create({
$$$
})'
Length of output: 97
Script:
#!/bin/bash
# Let's first find the stylesFn implementation
rg "stylesFn" -A 10
# Also check for any theme-related styles in the tag component
rg "StyleSheet.create" -A 10 components/ui/tag/
Length of output: 54686
Script:
#!/bin/bash
# Let's check the Tag styles implementation and its theme handling
rg -A 10 "Colors\(theme\)" styles/tag/Tag.styles.tsx
# Also check the Theme type definition to understand available theme properties
rg "type Theme" -A 5
Length of output: 570
Script:
#!/bin/bash
# Let's check the Colors utility to see how theme colors are defined
rg -A 10 "const Colors = \(theme\)" constants/Colors.ts
# Also check if there are any theme-specific color definitions
rg "tag:|tagForeground:" constants/Colors.ts
Length of output: 220
styles/Proposal.styles.tsx (1)
1-1: LGTM!
The Colors import is correctly placed and properly uses the module alias pattern.
styles/brand-item/BrandItem.styles.tsx (1)
14-14: Verify the asymmetric horizontal padding intention
The container has asymmetric horizontal padding (14px left, 8px right). Please confirm if this is intentional, as it might create visual imbalance.
✅ Verification successful
Based on the context gathered, I can now generate the final response:
The asymmetric padding is intentionally designed for the drawer menu layout
The asymmetric padding (14px left, 8px right) is part of a consistent drawer menu design where:
- BrandItem components are used within DrawerMenuContent as menu items
- The left padding (14px) aligns with the Searchbar's marginHorizontal
- The right padding (8px) provides space for the chevron icon in BrandActionItem
- Both BrandItem and BrandActionItem share the same styles and are used in a consistent layout pattern
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for similar asymmetric padding patterns in other components
# to verify if this is part of a broader design pattern
# Search for padding patterns in style files
rg -A 5 'paddingLeft|paddingRight' --glob '**/*.styles.{ts,tsx}'
Length of output: 980
Script:
#!/bin/bash
# Let's check the BrandItem component usage and its parent components
# to understand the context of this asymmetric padding
# First, find all files that import or reference BrandItem
rg -l "BrandItem" --type ts --type tsx
# Then, let's look for any design tokens or theme constants that might define these padding values
rg "(8|14)" --glob "**/theme/*.{ts,tsx}"
Length of output: 109
Script:
#!/bin/bash
# Let's try a different approach to find BrandItem usage and related components
# Using fd to find files first, then grep through them
# Find TypeScript/React files that mention BrandItem
fd -e ts -e tsx | xargs rg "BrandItem"
# Look for any design system or spacing constants
fd -e ts -e tsx | xargs rg "spacing|padding.*constant|SPACING|PADDING"
Length of output: 688
Script:
#!/bin/bash
# Let's examine the DrawerMenuContent to understand the context where BrandItem is used
cat components/drawer-layout/DrawerMenuContent.tsx
# Also check BrandActionItem since it shares the same styles
cat components/drawer-layout/BrandActionItem.tsx
Length of output: 6591
styles/empty-state/EmptyState.styles.tsx (2)
9-10: LGTM! Container spacing improvements look good.
The added horizontal padding and gap provide better content spacing and consistent layout.
26-26: LGTM! Consistent text alignment.
Centering both title and subtitle provides better visual harmony for empty states.
Also applies to: 30-30
utils/url.ts (2)
13-13: Consider externalizing the placeholder image path.
Hard-coding the placeholder image path creates tight coupling. Consider moving it to a configuration file.
Let's check if there's a central configuration file:
1-15: Verify usage of imageUrl function across the codebase.
Since this is a new function with specific return types, we should verify its integration with components that will consume it.
✅ Verification successful
Function implementation aligns with its usage across the codebase
The imageUrl function is correctly used in multiple components:
InfluencerCard.tsx: Used withinfluencer.profilePicand optional imagesempty-state/index.tsx: Used with optionalimagepropCollaborationHeader.tsx: Used with optionalcollaboration?.logorender-media-item.tsx: Used with URL strings (item.url || item.uri)
All usages align with the function's implementation which handles:
- URLs (starting with "http" or "ph://")
- NodeRequire objects
- Undefined values
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Find all files that might use the imageUrl function
rg -l "imageUrl" --type-add 'react:*.tsx' --type react
# Look for potential image-related components that might need to use this function
ast-grep --pattern 'source={$_}' --type-add 'react:*.tsx' --type react
Length of output: 479
Script:
#!/bin/bash
# Let's examine the usage of imageUrl in the identified files
echo "=== InfluencerCard.tsx ==="
rg "imageUrl" components/InfluencerCard.tsx -B 2 -A 2
echo -e "\n=== empty-state/index.tsx ==="
rg "imageUrl" components/ui/empty-state/index.tsx -B 2 -A 2
echo -e "\n=== CollaborationHeader.tsx ==="
rg "imageUrl" components/collaboration/CollaborationHeader.tsx -B 2 -A 2
echo -e "\n=== render-media-item.tsx ==="
rg "imageUrl" components/ui/carousel/render-media-item.tsx -B 2 -A 2
# Let's also check for Image component usage patterns to understand the expected prop types
echo -e "\n=== Image component usage patterns ==="
ast-grep --pattern 'Image source={$_}'
Length of output: 2330
constants/Themes/Theme.ts (1)
10-17: Verify completeness of Material Design color system tokens
The new color properties follow Material Design naming conventions, which is good. However, let's ensure all essential color tokens are present for a complete theme implementation.
Consider adding these commonly used Material Design color tokens if they're needed in your application:
errorandonErrorfor error statestertiaryandonTertiaryfor additional accent colorsoutlinefor component boundaries
components/collaborations/index.tsx (1)
29-31: Verify TopTabNavigation implementation.
Since TopTabNavigation is a new component, let's verify its implementation to ensure it properly handles tab switching and renders components correctly.
✅ Verification successful
TopTabNavigation implementation is properly integrated
The TopTabNavigation component is well-implemented with:
- Proper TypeScript interface for props (
TopTabNavigationProps) - Robust tab switching logic with scroll handling
- Consistent usage across collaboration components
- Proper state management for active tabs
- Responsive layout with support for different sizes ("compact" | "default")
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if TopTabNavigation component exists and verify its implementation
echo "Checking TopTabNavigation component implementation..."
ast-grep --pattern 'export $_ function TopTabNavigation' || ast-grep --pattern 'export $_ const TopTabNavigation'
# Check for proper prop types definition
echo "Checking for prop types..."
ast-grep --pattern 'interface $_Props {
tabs: $_
}'
# Check for proper tab handling logic
echo "Checking tab handling logic..."
rg -A 10 "const.*TopTabNavigation.*=.*{" components/ui/top-tab-navigation/
Length of output: 564
Script:
#!/bin/bash
# Let's try a different approach to locate the TopTabNavigation component
echo "Searching for TopTabNavigation files..."
fd -t f "top-tab-navigation" --exec ls -l
echo "\nSearching for TopTabNavigation usage and implementation..."
rg -l "TopTabNavigation"
echo "\nChecking component content..."
fd -t f "top-tab-navigation" --exec cat {}
Length of output: 540
Script:
#!/bin/bash
# Let's examine the actual implementation of TopTabNavigation
echo "Checking TopTabNavigation implementation:"
cat components/ui/top-tab-navigation/index.tsx
echo "\nChecking usage in collaboration components:"
echo "\n1. In collaborations/index.tsx:"
cat components/collaborations/index.tsx
echo "\n2. In collaboration-details/index.tsx:"
cat components/collaboration/collaboration-details/index.tsx
Length of output: 7602
components/contracts/index.tsx (2)
13-21: Fix typo in empty state message and verify navigation path
- There's a typo in the subtitle text: "Opps!" should be "Oops!"
- The navigation path "/collaborations" needs verification to ensure it exists
- subtitle="Opps! No Contracts has been created yet. Start applying to collaboration to get contracts."
+ subtitle="Oops! No Contracts have been created yet. Start applying to collaborations to get contracts."Let's verify the navigation path:
✅ Verification successful
Fix typo in empty state message
The navigation path "/collaborations" exists at app/(main)/(drawer)/(tabs)/collaborations.tsx, confirming it's a valid route. Please fix the typo and grammar in the subtitle text:
- subtitle="Opps! No Contracts has been created yet. Start applying to collaboration to get contracts."
+ subtitle="Oops! No Contracts have been created yet. Start applying to collaborations to get contracts."🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if the collaborations route exists
fd -e tsx -e ts -e js "collaborations\.(tsx|ts|js)" app/
Length of output: 104
7-8: 🛠️ Refactor suggestion
Add type annotation and verify data fetching implementation
The contracts array initialization raises two concerns:
- Missing type annotation for better type safety
- Hardcoded empty array suggests missing data fetching logic
Consider applying these changes:
- const contracts = [];
+ const contracts: Contract[] = []; // Add appropriate interface
+ // TODO: Implement data fetching logicLet's verify if there's any existing contracts fetching logic in the codebase:
styles/NotificationCard.styles.tsx (4)
8-8: LGTM! Improved spacing consistency
The padding update to 16 aligns better with standard design system spacing units.
26-26: LGTM! Consistent spacing
The marginLeft update maintains spacing consistency with other changes.
Line range hint 1-48: Verify notification handling strategy
Given that Toast components are being removed (as mentioned in the PR summary), please verify:
- How time-sensitive notifications are now handled
- Whether this NotificationCard component is intended to replace Toast functionality
- If any animation or auto-dismiss behavior needs to be added
11-14: Verify layout changes with different content lengths
The new contentContainer style improves spacing consistency. However, since this is a new addition, please verify the layout renders correctly with:
- Single line content
- Multi-line content
- Multiple notification items
✅ Verification successful
Layout changes are appropriately structured for all content variations
The contentContainer styles are correctly implemented and will work well with all content variations because:
- The gap of 16 provides consistent spacing between multiple notification cards in the ScrollView
- The paddingBottom of 24 ensures proper bottom spacing when scrolling through notifications
- The NotificationCard component has a robust structure that handles:
- Single-line content (title)
- Multi-line content (description and timestamp)
- Variable action buttons that appear conditionally
- The parent Notifications component properly uses these styles in both empty and populated states
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for NotificationCard usage to understand content variations
rg -l "NotificationCard" --type tsx
Length of output: 63
Script:
#!/bin/bash
# Search for NotificationCard usage with ripgrep, trying different file extensions
rg -l "NotificationCard" --type ts --type tsx --type jsx --type js
# Also search for the style file itself to confirm its existence
fd "NotificationCard.styles"
Length of output: 158
Script:
#!/bin/bash
# Search for NotificationCard usage with just file extensions
rg -l "NotificationCard" -g "*.ts" -g "*.tsx" -g "*.jsx" -g "*.js"
# Look at the content of the style file to understand the component structure
cat styles/NotificationCard.styles.tsx
Length of output: 1109
Script:
#!/bin/bash
# Let's look at the component implementation to understand the content structure
cat components/NotificationCard.tsx
# Also check the usage in notifications index
cat components/notifications/index.tsx
Length of output: 5119
app/(main)/(screens)/collaboration-details/[pageID].tsx (2)
1-6: LGTM! Clean and well-organized imports
The imports are properly organized and all imported entities are utilized in the component.
20-24: Verify the hardcoded cardType and snap points implementation
A few considerations about the BottomSheetActions implementation:
- The hardcoded
cardType="influencerCard"might need to be more flexible - The snap points range might need verification for optimal UX
Let's check how these values are used across the codebase:
✅ Verification successful
The hardcoded cardType is correct and snap points are consistently implemented
The verification reveals that:
- The
cardType="influencerCard"is intentionally hardcoded as it's part of a well-defined set of card types used across the application (influencerCard,applicationCard,invitationCard,activeCollab, etc.). Each type triggers specific actions in theBottomSheetActionscomponent. - The snap points implementation varies based on the use case:
["20%", "50%"]for influencer cards["50%", "90%"]for onboarding preferences
This variation is appropriate as different contexts require different sheet heights for optimal UX.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for other usages of BottomSheetActions and its props
ast-grep --pattern 'BottomSheetActions $$$cardType="$_"$$$'
# Check for different snap points configurations
ast-grep --pattern 'snapPointsRange={$_}'
Length of output: 105
Script:
#!/bin/bash
# Let's try a different approach to find BottomSheetActions usage
rg -A 3 "<BottomSheetActions"
# Also search for the component definition
ast-grep --pattern 'const BottomSheetActions = $_'
# And check for any type definitions related to cardType
rg "cardType.*=" -A 2
Length of output: 22257
styles/collaboration-details/CollaborationHeader.styles.tsx (3)
1-4: LGTM! Clean and well-organized imports.
The imports are properly structured with external dependencies first, followed by internal modules.
39-43: LGTM! Well-structured tag container styles.
The flex-wrap implementation provides a good responsive layout for tags.
11-24: Verify gap property support in target React Native versions.
The layout structure is well-organized, but the gap property might need a fallback for older React Native versions.
✅ Verification successful
The gap property is safe to use with React Native 0.74.3
The gap property is well-supported in React Native 0.74.3 and is consistently used throughout the codebase in multiple components and styles. The usage pattern shows it's a standard practice in this project, appearing in over 40 style definitions across various components. No fallback is needed.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check package.json for React Native version
rg '"react-native":\s*"([^"]+)"' -o | head -n1
Length of output: 86
Script:
#!/bin/bash
# Check if there are any existing fallbacks or alternative spacing approaches in the codebase
rg -B2 -A2 'gap:.*\d+' --type tsx --type ts
Length of output: 73
Script:
#!/bin/bash
# Check for gap usage patterns in style files, correcting the file type
rg -B2 -A2 'gap:' .
Length of output: 14232
components/ui/menu-icon/index.tsx (1)
23-26: Verify icon size consistency
The icon size has been changed from 25 to 24. While this change is minor, let's verify if this new size is consistent with other navigation icons in the app.
styles/FilterModal.styles.tsx (1)
9-10: LGTM! The padding split provides better layout control.
The separation of padding into horizontal and vertical components allows for more precise layout control, following React Native best practices.
styles/CollaborationCard.styles.tsx (3)
8-8: Verify the removal of card elevation
The removal of elevation and setting transparent shadow will make the card appear flat. Please confirm if this aligns with the new design system, as it might impact the visual hierarchy and depth perception of the UI.
Consider maintaining some subtle elevation to help distinguish the card from its background, especially in cases where the card and background colors are similar.
Also applies to: 10-10
25-25: LGTM! Good improvement to layout flexibility
Adding flex: 1 to the collaboration name style is a good practice that ensures proper text truncation and flexible layout behavior.
Line range hint 1-61: Verify cleanup of removed styles
The AI summary mentions that the bookmarkIcon style was removed, but we can't see it in the changes. Let's verify that it's not being used elsewhere in the codebase.
✅ Verification successful
Removed styles are safely deleted
The git diff confirms that bookmarkIcon style was removed along with other styles (chip and divider). After checking the component file, none of these removed styles are being used in the CollaborationCard component, confirming this is a safe cleanup.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any remaining references to bookmarkIcon
rg -i "bookmarkIcon" --type tsx --type ts
Length of output: 69
Script:
#!/bin/bash
# Search for any remaining references to bookmarkIcon using ripgrep without file type filters
rg -i "bookmarkIcon"
# Also search for the component file that might be using these styles
fd -e tsx -e ts "CollaborationCard"
Length of output: 139
Script:
#!/bin/bash
# Let's check the component file to see if it's using any removed styles
cat components/collaboration/CollaborationCard.tsx
# Also get the git history of the styles file to see what was removed
git diff HEAD^ styles/CollaborationCard.styles.tsx
Length of output: 5005
styles/top-tab-navigation/TopTabNavigation.styles.tsx (2)
43-52: LGTM! Well-structured compact styles.
The compact styles follow a good pattern for responsive design, providing a consistent way to render a more condensed version of the tabs.
53-55: LGTM! Appropriate content styling.
The flex: 1 style is appropriate for ensuring the content takes up the available space.
constants/Colors.ts (1)
16-19: Review color contrast ratios for accessibility.
The dark theme colors need review for the following concerns:
primaryandonSurfaceshare the same value (#538BA6), which might not follow Material Design principles where surface colors typically contrast with their "on" colors.- The contrast ratio between tag (#5f6368) and tagForeground (#f1f3f4) should be verified for accessibility.
components/notifications/notification-icon.tsx (2)
9-10: LGTM: FontAwesome imports
The new imports for FontAwesome's React Native integration are correctly added.
43-46: LGTM: Icon implementation
The FontAwesomeIcon implementation is correct with proper:
- Color inheritance from theme
- Icon specification using faBell
- Size specification
- Opacity handling for pressed state
components/ui/empty-state/index.tsx (3)
21-33: LGTM!
Clean props destructuring with sensible defaults and proper hook initialization.
17-17: Consider keeping the title prop required
Making the title optional might lead to empty states without clear messaging for users. Consider keeping it required unless there's a specific use case for empty titles.
34-40: Consider handling navigation edge cases
The fallback to navigation.goBack() might fail if there's no navigation history. Consider adding a safety check or providing a default route.
const handleAction = () => {
if (action) {
action();
} else {
- navigation.goBack();
+ if (navigation.canGoBack()) {
+ navigation.goBack();
+ } else {
+ // Navigate to a safe default route
+ navigation.navigate('Home');
+ }
}
};styles/tab1.styles.tsx (1)
16-19: Verify skip button's visibility and accessibility
The skipButtonContainer now only contains positioning properties. Ensure that the skip button remains visible and accessible without the previously removed styling properties (background, padding, border radius).
components/drawer-layout/DrawerMenuItem.tsx (1)
6-7: Verify the impact of IconProp type change across the codebase
The change from string to IconProp for the icon property improves type safety but could be a breaking change.
Let's verify all usages of this component to ensure they've been updated:
Also applies to: 11-11
✅ Verification successful
Let me gather more information to verify the impact of this change.
Let me check how the tabs are defined and passed to DrawerMenuItem through DrawerMenuContent.
Let me try one final search to find any tab or icon definitions in the codebase.
Based on the gathered information, I can now provide the final response:
Type change to IconProp appears to be properly contained
The change from string to IconProp is localized and properly managed:
- DrawerMenuItem is only imported and used in DrawerMenuContent.tsx
- The IconProp type is correctly imported and used in the Tab type definition
- No other components in the codebase are using IconProp, suggesting this is an isolated change
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for DrawerMenuItem usage patterns
rg -l "DrawerMenuItem" | xargs rg -A 5 "icon:\s*['\"]"
# Search for any Tab type usage
ast-grep --pattern 'type Tab = {
$$$
}'
Length of output: 401
Script:
#!/bin/bash
# Search for DrawerMenuItem component usage
rg -A 2 "<DrawerMenuItem"
# Search for any icon prop assignments to DrawerMenuItem
rg "icon=" --context 2 "DrawerMenuItem"
# Search for any imports of DrawerMenuItem
rg -A 1 "import.*DrawerMenuItem"
Length of output: 825
Script:
#!/bin/bash
# Search for tabs definition in DrawerMenuContent
rg -A 10 "const.*tabs.*=.*\[" components/drawer-layout/DrawerMenuContent.tsx
# Search for any other files that might define these tabs
rg -g '!DrawerMenuContent.tsx' -A 5 "icon:.*['\"]"
Length of output: 133
Script:
#!/bin/bash
# Search for any array containing icon definitions
rg -A 5 "\[\s*{\s*(icon|href|label):"
# Search for any IconProp type usage
rg "IconProp"
# Search for any FontAwesome icon assignments
rg "icon:\s*[\"\']fa[rls]?-"
Length of output: 469
components/collaboration/CollaborationHeader.tsx (1)
7-7: Verify style definitions and theme typing
Let's ensure the imported styles are properly defined and typed.
✅ Verification successful
Style definitions and theme typing are properly implemented
The verification shows that:
- The file exists at the correct location:
styles/collaboration-details/CollaborationHeader.styles.tsx - The style file properly imports and uses the Theme type from @react-navigation/native
- The stylesFn is correctly exported and typed with the Theme parameter
- The component correctly imports and uses the theme-aware styles
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if styles file exists and contains proper theme typing
rg -l "stylesFn.*Theme" "styles/collaboration-details/CollaborationHeader.styles.ts"
# Verify theme type usage
ast-grep --pattern 'interface $_ extends Theme {
$$$
}'
Length of output: 243
Script:
#!/bin/bash
# Let's first check if the file exists in a different location
fd "CollaborationHeader.styles"
# Search for any stylesFn exports in the codebase
rg "export.*stylesFn"
# Look for Theme imports and interfaces
rg "import.*Theme" -A 2
Length of output: 30380
components/ui/brand-switcher/index.tsx (2)
4-5: LGTM: Clean import restructuring
The switch to FontAwesome icons aligns well with the standardization effort across the application.
40-43: Verify icon standardization across similar components
Let's ensure this icon implementation is consistent with other similar components in the codebase.
✅ Verification successful
Icon implementation is consistent across components
The FontAwesomeIcon usage in brand-switcher follows the same pattern as other components in the codebase:
- Consistent import from "@fortawesome/react-native-fontawesome"
- Standard props pattern using
color,icon, andsize - Consistent color handling using
Colors(theme).textfor UI components - Similar icon size values (20-24px range)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other FontAwesomeIcon usage patterns in similar UI components
rg -l "FontAwesomeIcon" --type tsx | while read -r file; do
echo "=== $file ==="
rg "FontAwesomeIcon" -A 2 "$file"
done
Length of output: 77
Script:
#!/bin/bash
# Search for FontAwesomeIcon usage patterns in all files
rg -l "FontAwesomeIcon" | while read -r file; do
echo "=== $file ==="
rg "FontAwesomeIcon" -A 2 "$file"
done
Length of output: 5175
styles/onboarding/brand.styles.tsx (2)
33-33: Consider accessibility implications
The switch to primary color for the border might affect color contrast ratios. Please verify that the input remains clearly visible against different background colors and meets WCAG accessibility guidelines.
Consider implementing contrast ratio checks in your CI pipeline to automatically verify accessibility compliance. Would you like assistance in setting this up?
33-33: Verify alignment with design system
The change from border color to primary color makes the input more prominent. While this change aligns with the theme update objective, please ensure this styling is consistent with other autocomplete inputs across the application.
✅ Verification successful
Let me generate another verification script to search for similar input containers and their border colors across the codebase.
Let me try one final search with a different approach to find styling patterns.
Based on the comprehensive search results, I can now make a determination about the border color change. Looking at the codebase:
- The change from
Colors(theme).bordertoColors(theme).primaryappears to be an intentional styling update for the autocomplete input container. - Other components in the codebase use different border colors based on their specific needs (e.g.,
Colors(theme).aliceBlue,Colors(theme).text, etc.). - There's no consistent pattern requiring all input containers to use the same border color.
- The autocomplete input is a standalone component with its own styling requirements.
Border color change is acceptable
The change from neutral border to primary color for this specific autocomplete input is appropriate as:
- It's a localized styling change that doesn't affect other components
- Input containers across the codebase use various border colors based on their individual design needs
- The primary color will make this input more prominent, which may be desirable for its specific use case
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Search for other autocomplete input containers to verify styling consistency
# Look for similar style definitions in other files
# Search for autocomplete input container styles
rg -t tsx -t ts "autocompleteInputContainer.*borderColor.*Colors\(theme\)" --glob '!styles/onboarding/brand.styles.tsx'
# Search for similar components using ast-grep
ast-grep --pattern 'StyleSheet.create({
$$$
autocompleteInputContainer: {
$$$
borderColor: $_,
$$$
},
$$$
})'
Length of output: 5175
Script:
#!/bin/bash
# Search for any input container styles with border colors to compare styling patterns
rg -t ts -t tsx "borderColor.*Colors\(theme\)" -B 2 -A 1
# Search specifically for input-related containers with border colors
ast-grep --pattern '{
$$$
input$_: {
$$$
borderColor: $_,
$$$
}
}'
Length of output: 173
Script:
#!/bin/bash
# Search for all style definitions containing Colors(theme) to understand the color usage pattern
fd -e tsx -e ts -x grep -l "Colors(theme)" {} | xargs cat
# Alternative pattern search for border-related styles
ast-grep --pattern 'StyleSheet.create({
$$$
border$_: $_,
$$$
})'
Length of output: 131206
constants/Influencers.ts (1)
Line range hint 11-12: Add error handling for external image URLs
The profile pictures and media URLs point to external services. Consider:
- Adding fallback images
- Implementing image loading error handling
- Using a CDN or internal asset storage for production
Also applies to: 42-43
✅ Verification successful
Let me check how these URLs are being used in the codebase to understand the implementation better.
External image URLs need proper error handling, but fallback mechanism exists
The codebase already has a fallback mechanism implemented with local placeholder images:
- Default placeholder:
@/assets/images/placeholder-image.jpg - Person placeholder:
@/assets/images/placeholder-person-image.png - Cover placeholder:
@/assets/images/cover-placeholder-image.png
However, the external URLs in Influencers.ts should utilize this existing fallback system. Consider:
- Using the
getImageUrlutility fromutils/url.tswhich already handles fallbacks - Moving the external images to a CDN in production for better reliability
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for other instances of hardcoded external URLs in the codebase
rg -g '*.{ts,tsx,js,jsx}' 'https://img.freepik.com|https://picsum.photos'
Length of output: 935
Script:
#!/bin/bash
# Check for image handling components and utilities
rg -g '*.{ts,tsx,js,jsx}' -B 2 -A 2 'onError|fallback|placeholder|loading.*image'
# Check Image component usage
ast-grep --pattern 'Image source={$_}'
Length of output: 6454
styles/InfluencerCard.styles.tsx (2)
14-16: LGTM! Good use of gap for spacing
The header styling changes improve the layout consistency by using the gap property for spacing elements.
74-80: LGTM! Good layout structure
The new layout structure with separate stats and statsContainer provides better organization and spacing control.
styles/collaboration-details/CollaborationDetails.styles.tsx (3)
85-85: LGTM! Good use of theme-based colors.
The change to use theme-based border color improves consistency with the app's theming system.
50-53: Verify the shadow removal intention and clean up unused properties.
The shadow color is set to transparent, but according to the AI summary, other shadow-related properties were removed. This might indicate a move towards a flatter UI design.
If the intention is to remove shadows completely, consider removing all shadow-related properties for cleaner code. Run this script to verify shadow-related properties across style files:
✅ Verification successful
Let me gather more context about the specific file to understand if there are any remaining shadow properties.
Shadow properties are properly cleaned up in this component
The verification shows that in CollaborationDetails.styles.tsx, shadowColor is the only shadow-related property present, and it's set to transparent. There are no lingering shadow properties like shadowOffset, shadowOpacity, shadowRadius, or elevation that would need cleanup.
Looking at the broader codebase context:
- Some components like modals and Tab1 maintain full shadow implementations
- Other cards (CollaborationCard, NotificationCard) also use transparent shadows
- This suggests an intentional design pattern where certain components are flat while others maintain elevation
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for shadow-related properties in style files
rg -i 'shadow(Color|Offset|Opacity|Radius)|elevation' 'styles/'
Length of output: 1126
Script:
#!/bin/bash
# Check the full style object in CollaborationDetails.styles.tsx
rg -A 10 -B 10 'shadowColor: Colors\(theme\)\.transparent' styles/collaboration-details/CollaborationDetails.styles.tsx
Length of output: 555
Line range hint 1-97: Verify the impact of removed styles.
The AI summary indicates that several styles (profileCard, profileContent, name, statChip) were removed. Let's verify these aren't used anymore.
✅ Verification successful
The removed styles are not used in the codebase
The search results show that while there are many occurrences of "name", "profileCard", "profileContent", and "statChip" in the codebase, none of them refer to the removed style properties from CollaborationDetails.styles.tsx. The occurrences are either:
- Component props and data properties
- Different style objects in other components
- Route/screen names
- File paths
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for usage of removed styles
rg -l 'styles\.(profileCard|profileContent|name|statChip)' --type tsx
Length of output: 99
Script:
#!/bin/bash
# Check for usage of removed styles with proper file extension
rg -l 'styles\.(profileCard|profileContent|name|statChip)' --type ts --type tsx --type jsx --type js
# Also search for any direct references to these style names
rg -l '(profileCard|profileContent|name|statChip):\s*{' --type ts --type tsx --type jsx --type js
Length of output: 388
Script:
#!/bin/bash
# Search for any usage of the removed style names in all files
rg "profileCard|profileContent|name|statChip" -g "*.ts" -g "*.tsx" -g "*.js" -g "*.jsx" -C 2
Length of output: 26897
components/SearchComponent.tsx (1)
2-7: LGTM! Good improvements to the imports
The switch to Pressable and standardization of icons with FontAwesome are good improvements. The Theme type import properly supports the new theme-aware styling.
components/notifications/index.tsx (2)
39-62: LGTM! Well-structured notification list implementation
The ScrollView implementation with NotificationCard mapping is clean and efficient:
- Proper style management with contentContainerStyle
- Correct data passing to NotificationCard components
- Appropriate callback handling
40-41: Verify style definitions exist
The component references styles.container and styles.contentContainer. Let's ensure these styles are properly defined in the stylesFn.
✅ Verification successful
Style definitions are properly implemented
The container and contentContainer styles are correctly defined in styles/NotificationCard.styles.tsx and properly imported and used in the component. The styles are created using StyleSheet.create with appropriate properties:
containerhas flex, padding, and background colorcontentContainerhas gap and bottom padding
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for container and contentContainer style definitions
rg -A 5 "stylesFn.*=.*{" "@/styles/NotificationCard.styles"
Length of output: 151
Script:
#!/bin/bash
# First, let's find the styles file in the repository
fd "NotificationCard.styles"
# Then search for style definitions in the components directory
rg -A 5 "styles\s*=\s*{|StyleSheet.create\s*\(" "components/notifications/"
Length of output: 273
Script:
#!/bin/bash
# Let's check the content of the styles file
cat styles/NotificationCard.styles.tsx
# Also check the component file for inline styles
cat components/notifications/index.tsx
Length of output: 3102
components/drawer-layout/BrandItem.tsx (1)
6-8: LGTM! Clean import structure
The transition to FontAwesome icons while maintaining necessary react-native-paper components shows a thoughtful migration approach.
components/channel/channel-list.tsx (1)
54-55: LGTM! Standardized padding values.
The change to use consistent padding values (16) aligns with common design system practices. However, please verify that reducing the top padding from 20 to 16 doesn't negatively impact the visual spacing with elements above this view.
✅ Verification successful
Padding standardization aligns with codebase patterns
The change to use padding: 16 and paddingTop: 16 in channel-list.tsx is consistent with the codebase's patterns. The search results show that:
- 16px padding is commonly used (NotificationCard, CollaborationCard, UploadModal, etc.)
- Top padding values vary between 8px and 16px for similar list/content components
- The previous value of 20px is typically used for more prominent containers like modals and full-screen views
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for other components using similar padding patterns
# to ensure consistency across the codebase
# Search for padding declarations in TSX/JSX files
rg -t tsx -t jsx 'padding(?:Top)?: \d+' --no-filename | sort | uniq -c | sort -nr
Length of output: 111
Script:
#!/bin/bash
# Search for padding patterns in all files, not relying on file extensions
rg 'padding(?:Top)?: \d+' --type-add 'frontend:*.{tsx,jsx,ts,js}' -t frontend
Length of output: 2629
components/ui/carousel/render-media-item.tsx (1)
1-14: LGTM! Imports are well-organized and necessary.
The imports are properly structured, separating external dependencies from internal utilities.
components/ui/carousel/carousel.tsx (1)
21-23: LGTM! Well-structured state management
The state variables are well-defined with clear purposes and proper typing.
styles/modal/UploadModal.styles.tsx (1)
79-82: LGTM! Good improvements to layout flexibility
The changes from fixed widths to flex layout and from space-between to gap spacing improve the component's maintainability and flexibility.
components/collaboration/collaboration-details/OverviewTabContent.tsx (1)
16-21: LGTM!
Component declaration and theme setup are properly implemented.
package.json (1)
71-71: Verify compatibility with Font Awesome integration
Changing react-native-svg from fixed version "15.2.0" to "^15.2.0" could introduce breaking changes through minor updates. Please verify compatibility with the Font Awesome integration.
✅ Verification successful
Using react-native-svg ^15.2.0 is safe with Font Awesome integration
The codebase uses @fortawesome/react-native-fontawesome v0.3.2, which requires react-native-svg >= 11.x. Since v15.2.0 satisfies this requirement and no breaking changes were found in the react-native-svg repository that would affect Font Awesome integration, the version change is safe. The extensive usage of FontAwesomeIcon across multiple components is working with the current setup and will continue to work with minor updates to v15.x.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check compatibility between react-native-svg and @fortawesome/react-native-fontawesome
# Get the latest compatible version of react-native-svg from Font Awesome's package.json
curl -s https://registry.npmjs.org/@fortawesome/react-native-fontawesome/latest | jq -r '.peerDependencies["react-native-svg"]'
# Check for any reported issues or breaking changes
gh api graphql -f query='
{
search(query: "repo:react-native-svg/react-native-svg is:issue label:breaking-change", type: ISSUE, first: 5) {
nodes {
... on Issue {
title
url
labels(first: 5) {
nodes {
name
}
}
}
}
}
}'
Length of output: 478
Script:
#!/bin/bash
# Let's verify if Font Awesome is actually used in the codebase and check its version
rg -l "@fortawesome/react-native-fontawesome"
# Check the actual version of Font Awesome being used
cat package.json | jq '.dependencies["@fortawesome/react-native-fontawesome"], .devDependencies["@fortawesome/react-native-fontawesome"]'
# Look for any Font Awesome icon usage in the code
rg "FontAwesomeIcon|createIconSet" -A 2
Length of output: 7227
app/(public)/pre-signin.tsx (2)
1-4: LGTM! Import cleanup and Button component addition
The import changes align with the theme update objectives, removing unused imports and adding the Button component from react-native-paper.
62-63: Verify the skipButtonContainer styles
Please ensure that the skipButtonContainer style is properly defined in the styles object.
✅ Verification successful
Let me verify if this style is properly imported in the pre-signin.tsx file.
The skipButtonContainer style is properly defined and imported
The style is correctly defined in styles/tab1.styles.tsx and properly imported in pre-signin.tsx as stylesFn. The style definition includes the necessary positioning properties.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for skipButtonContainer style definition
rg -A 5 "skipButtonContainer.*[:=]"
Length of output: 291
Script:
#!/bin/bash
# Check imports and style usage in pre-signin.tsx
rg -A 5 "import.*styles.*tab1\.styles" app/\(public\)/pre-signin.tsx
Length of output: 341
components/collaboration/CollaborationCard.tsx (2)
1-12: LGTM! Import changes align with component refactoring
The changes streamline the imports by removing unused hooks and replacing icon libraries, which aligns well with the refactoring objectives.
49-63: Verify the ellipsis button alignment
The justifyContent and alignItems changes to "flex-start" might affect the ellipsis button's positioning. Please ensure this doesn't create unintended layout shifts.
Consider using predefined style constants for consistent spacing:
- justifyContent: "flex-start",
- alignItems: "flex-start",
+ justifyContent: "center",
+ alignItems: "center",app/(main)/(drawer)/(tabs)/_layout.tsx (4)
13-23: LGTM! Clean organization of FontAwesome imports.
The separation between regular and solid icons is well-structured, making it clear which icon variants are being used throughout the component.
38-38: LGTM! Improved tab bar spacing.
The added horizontal padding enhances the visual spacing between tab items.
129-133: LGTM! Consistent icon implementation.
The Messages and Contracts tabs maintain consistent icon sizing and styling patterns.
Also applies to: 145-149
Line range hint 107-123: Verify deep linking support for the create collaboration modal.
The current implementation prevents default tab navigation and pushes to a modal route. Ensure this pattern supports deep linking scenarios.
✅ Verification successful
Let me gather more information about the navigation setup and deep linking configuration.
Let me check one more thing about the navigation setup, particularly focusing on the modal routes and their configuration.
Deep linking support appears to be properly configured
The app has a URL scheme ("myapp") defined in app.json, which is a prerequisite for deep linking. The modal navigation pattern using router.push to "/(modal)/create-collaboration" is a standard approach in Expo Router, which inherently supports deep linking through its file-system based routing. The implementation follows the recommended patterns for modal presentation in Expo Router.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for deep linking configuration and modal route definition
rg -A 5 "create-collaboration" app/\(modal\)
Length of output: 639
Script:
#!/bin/bash
# Check for deep linking configuration in app config and navigation setup
rg -A 5 "linking|Linking" app.json app/\(_layout|expo-router\)
rg -A 5 "scheme" app.json
Length of output: 440
Script:
#!/bin/bash
# Check for modal route configuration and navigation setup
rg -A 10 "Stack.Screen.*create-collaboration" app/
rg -A 10 "Tabs.Screen.*create-collaboration" app/
Length of output: 104
components/explore-influencers/index.tsx (2)
10-11: LGTM: Theme integration follows best practices
The addition of theme support using React Navigation's useTheme hook and centralized color management is well-implemented.
Also applies to: 28-28
73-74: Verify the impact of reduced bottom padding
The bottom padding has been reduced from 100 to 16. Please verify that this doesn't affect the visibility of list items when used with bottom navigation or floating action buttons.
✅ Verification successful
Reduced bottom padding is safe to use
The reduced bottom padding from 100 to 16 is appropriate because:
- The FlatList is wrapped in
AppLayoutwhich likely handles the main layout spacing - The BottomSheetActions component is rendered conditionally and uses absolute positioning with its own bottom spacing
- The FlatList has proper item separation with 16px height between items
- No fixed bottom navigation or floating buttons are present in the component that would require extra padding
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for bottom navigation or floating elements that might be affected
rg -t tsx -t jsx "position: *['\"]absolute['\"].*bottom:|bottom: *[0-9]" ./components/
Length of output: 120
Script:
#!/bin/bash
# Search for bottom navigation or floating elements with different pattern
rg "position.*absolute.*bottom|bottom:.*\d+" ./components/
# Also check for any FlatList components that might have similar padding patterns
rg "FlatList.*padding" ./components/
Length of output: 210
Script:
#!/bin/bash
# Let's check the context of the FlatList in the file under review
cat ./components/explore-influencers/index.tsx
# Also check if there are any bottom sheets or navigation components that might overlap
rg -A 5 "BottomSheetActions|BottomNavigation|TabBar" ./components/
Length of output: 11634
app/(onboarding)/onboarding-brand-preference.tsx (1)
93-98: Verify the skip flow implementation
Let's verify if skipping preferences is properly handled throughout the onboarding flow.
✅ Verification successful
Let me gather more information about the skip functionality and preferences handling.
Let me check one more aspect to understand the flow between screens and preference handling.
Based on the gathered information, I can now provide a final response about the skip flow implementation.
Skip functionality is properly implemented but needs documentation
The skip flow is correctly implemented with:
handleSignUp()function that callsfirebaseSignInwith the current user's ID- Navigation flow from brand preferences to main app (
/(main)/explore-influencers) - Proper state management through
useAuthContext
However, for better maintainability:
- Consider adding comments explaining the skip behavior's impact on user preferences
- Document that skipped preferences can be updated later in
app/(main)/(screens)/(menu)/preferences.tsx
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other onboarding screens to understand the flow
rg -t tsx -l "AppLayout.*onboarding" app/
# Check if other screens handle skipped preferences
rg -A 5 "preferences" app/
Length of output: 1098
Script:
#!/bin/bash
# Check for skip-related functionality in onboarding
rg -A 5 "handleSignUp|onSkip" app/
# Look for preferences component implementation
ast-grep --pattern 'export default function Preferences() {
$$$
}'
# Check for any preference state management
rg -A 5 "preferences.*State|usePreferences" app/
Length of output: 2770
Script:
#!/bin/bash
# Check for navigation and routing related to onboarding
rg -A 5 "router.push|router.replace|navigation" app/\(onboarding\)/
# Look for firebase-related preference handling
rg -A 5 "firebaseSignIn" app/
Length of output: 4487
app/(onboarding)/onboarding-get-started.tsx (2)
7-8: LGTM! Import organization follows good practices.
The reorganization places core React Native imports before third-party ones, which is a common convention.
86-92: Verify skip functionality impact on user onboarding
The skip button bypasses the survey data collection. Consider:
- Whether this affects any downstream features that might depend on this data
- If we should persist a "skipped" state to differentiate these users
✅ Verification successful
Skip functionality is safe to use
The skip button's implementation is appropriate as:
- Survey data is only used for brand profiling and stored in the "brands" collection
- No critical downstream features depend on this data
- The
handleSignUp()function still ensures proper user authentication - Users are correctly redirected regardless of survey completion
The survey appears to be optional analytics data rather than critical user information, making the skip functionality a valid user flow.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for usage of survey data in the codebase
rg -l "survey\." --type ts --type tsx | xargs rg "survey\."
Length of output: 89
Script:
#!/bin/bash
# Search for survey-related patterns in TypeScript files
rg -t ts "survey" -i
# Search for any data persistence or state management related to onboarding
rg -t ts "onboarding.*state|onboarding.*data" -i
# Look for skip-related functionality in onboarding
rg -t ts "skip.*onboarding|onboarding.*skip" -i
Length of output: 545
Script:
#!/bin/bash
# Check the onboarding file content for survey data structure and usage
cat "app/(onboarding)/onboarding-get-started.tsx"
# Look for any state management or context files
fd -e ts -e tsx "(state|context|store)" --type f
# Search for any API or data persistence related to onboarding
rg -t ts "onboarding.*api|onboarding.*service|onboarding.*storage" -i
Length of output: 7164
components/proposals/Invitations.tsx (2)
1-20: LGTM! Clean and well-organized imports
The imports are properly structured and all are being utilized in the component.
142-189: LGTM! Well-structured FlatList implementation
The FlatList implementation is clean with proper refresh control and well-organized styling properties.
app/(onboarding)/onboarding-your-brand.tsx (3)
6-6: LGTM! Good choice using Pressable.
The switch to Pressable from TouchableOpacity is a good modernization. Pressable provides more flexibility and better control over touch interactions.
203-203: Same styling improvement applies here.
The same inline styles improvement suggested for the role selection applies to this industry selection implementation.
Also applies to: 208-219
Line range hint 1-250: Verify complete removal of Toast component.
The AI summary mentions the removal of the Toast component, but let's verify there are no remaining Toast-related imports or remnants in the codebase.
✅ Verification successful
Toast component has been properly migrated to Toaster
The codebase shows a consistent pattern where the old Toast component is only used as a wrapper in the app layout (layouts/app-layout/index.tsx), while all actual toast notifications are handled through the new Toaster utility (@/shared-uis/components/toaster/Toaster). This is the correct implementation as per the changes.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any remaining Toast-related code
rg -i "toast" --type tsx --type ts
Length of output: 62
Script:
#!/bin/bash
# Search for any Toast or Toaster related code in all files
rg -i "toast"
Length of output: 3922
components/FilterModal.tsx (4)
10-12: LGTM: Icon library migration and prop updates
Clean migration from Ionicons to FontAwesome icons with proper typing.
113-117: LGTM: Clean icon implementation
Proper implementation of FontAwesome icon with theme-based colors.
121-123: Verify nested scrolling behavior
Using flex: 1 within a BottomSheet's ScrollView might cause nested scrolling issues. Consider testing the following scenarios:
- Content overflow behavior
- Interaction between BottomSheet drag and scroll
- Scroll gesture conflicts
101-106: Verify color contrast for accessibility
The handle indicator's visibility might be affected by the theme colors. Ensure sufficient contrast ratio between background and indicator colors for accessibility.
✅ Verification successful
Color contrast is sufficient for accessibility
Based on the Colors definition, the contrast is adequate:
- Light theme: black text (#000) on white background (#fff)
- Dark theme: white text (#fff) on black background (#000)
These combinations provide maximum contrast ratios (21:1), well above the WCAG AAA requirement of 7:1 for normal text.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other theme color usage patterns to compare
rg -g '*.{ts,tsx}' "Colors\(theme\)\.background.*Colors\(theme\)\.text" .
Length of output: 75
Script:
#!/bin/bash
# Let's search for the Colors utility function and theme color definitions
rg -g '*.{ts,tsx}' "export.*Colors.*theme" -A 10
Length of output: 50
Script:
#!/bin/bash
# Search for any color contrast or accessibility related tests
rg -g '*.{test,spec}.{ts,tsx}' -i "contrast|a11y|accessibility"
Length of output: 214
Script:
#!/bin/bash
# Look for the theme type definitions
fd -e ts -e tsx "theme|colors" --type f --exec rg -l "interface.*Theme|type.*Theme|export.*Colors"
Length of output: 130
Script:
#!/bin/bash
# Let's examine the theme definitions file we found
cat ./components/theme/Themed.tsx
Length of output: 1346
Script:
#!/bin/bash
# Search for any other usage of Colors in FilterModal
rg -g "FilterModal.tsx" "Colors\(theme\)" -B 2 -A 2
Length of output: 1663
Script:
#!/bin/bash
# Let's check the Colors constant definition
cat @/constants/Colors.ts || cat constants/Colors.ts
Length of output: 1600
Script:
#!/bin/bash
# Search for any theme-related configuration or setup
fd -e ts -e tsx -e js -e json "theme|colors" --type f --exec rg -l "defaultTheme|ThemeProvider|createTheme"
Length of output: 178
components/collaboration/collaboration-details/InvitationsTabContent.tsx (2)
214-214: Verify the cardId prop passed to BottomSheetActions
Passing the entire selectedInfluencer object as cardId may not be appropriate if BottomSheetActions expects an identifier. Ensure that the component expects an object; otherwise, pass the correct identifier.
99-99:
Remove unnecessary semicolon after the if block
The semicolon after the closing brace of the if statement is unnecessary and could lead to syntax errors. It should be removed.
Apply this diff to fix the issue:
-};
+}Likely invalid or redundant comment.
components/InfluencerCard.tsx (2)
125-128:
Confirm the imageUrl utility function compatibility with Avatar.Image
The Avatar.Image component receives source as imageUrl(influencer.profilePic). Ensure that imageUrl returns an object compatible with the source prop expected by Avatar.Image, which typically requires an object like { uri: string }.
If imageUrl does not return the correct format, consider updating it or adjusting the usage.
Apply this diff if necessary:
<Avatar.Image
size={50}
- source={imageUrl(influencer.profilePic)}
+ source={{ uri: imageUrl(influencer.profilePic) }}
/>26-31: Verify the imported module paths and component existence
Ensure that the imported modules such as CarouselNative, convertToKUnits, FontAwesomeIcon, and Tag are correctly installed and the paths are accurate. This prevents runtime errors due to missing modules or incorrect import paths.
Run the following script to verify the existence of the imported modules:
✅ Verification successful
All imported modules are correctly configured and available
CarouselNativeexists at./components/ui/carousel/carousel.tsxconvertToKUnitsutility exists at./utils/conversion.tsTagcomponent exists at./components/ui/tag/index.tsxFontAwesomeIconand its icons are properly installed (all required @FortAwesome packages are in package.json)imageUrlutility exists at./utils/url.ts
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if the imported modules exist at the specified paths.
# Verify CarouselNative import
fd 'carousel.tsx' ./components
# Verify convertToKUnits import
fd 'conversion.ts' ./utils
# Verify Tag component import
fd 'tag.tsx' ./components/ui
# Verify FontAwesomeIcon module
npm ls @fortawesome/react-native-fontawesome
Length of output: 246
Script:
#!/bin/bash
# Let's verify the tag component and check its content
rg -g '*.tsx' -g '*.ts' 'export.*Tag' -A 2
# Check if FontAwesome icons are used elsewhere in the codebase
rg -g '*.tsx' -g '*.ts' '@fortawesome/.*-fontawesome'
# Check the actual content of the carousel component
cat "./components/ui/carousel/carousel.tsx"
# Check the content of conversion utility
cat "./utils/conversion.ts"
Length of output: 3659
Script:
#!/bin/bash
# Let's verify the Tag component's existence and implementation
cat "./components/ui/tag/index.tsx"
# Check if the imageUrl utility exists and its implementation
cat "./utils/url.ts"
# Verify FontAwesome icon package in package.json
cat package.json | grep -A 5 -B 5 "@fortawesome"
Length of output: 1829
app/(modal)/create-collaboration.tsx (4)
81-84: Good Practice: Added Input Validation for Adding Links
Adding validation to check that both newLinkName and newLinkUrl are filled before adding a link improves the robustness of the addLink function.
158-159: Verify Compatibility of the 'gap' Style Property
The gap property used in the contentContainerStyle of ScrollView might not be supported on all platforms or older versions of React Native. This could lead to layout issues on unsupported devices.
Please confirm that the gap property is compatible with all target platforms or consider using alternative styling methods, such as margin or padding, to ensure consistent spacing.
168-176: Ensure Back Button Visibility on All Platforms
The back navigation button is conditionally rendered only on web platforms:
Platform.OS === "web" && (
<IconButton ... />
)Verify that users on mobile platforms (iOS and Android) have an intuitive way to navigate back. If not, consider rendering the back button on all platforms or implementing platform-specific navigation solutions.
261-285: Ensure 'Select' Components Match Expected Selection Behavior
You've replaced RadioButton groups with Select components for Promotion Type, Collaboration Type, and Platform. If these fields are intended for single selection, ensure that the Select component is configured to allow only single selection to prevent user confusion.
Check if the Select component has a prop to enforce single selection or adjust the component to handle multiple selections appropriately.
| export const convertToKUnits = (num: number) => { | ||
| if (num >= 1000) { | ||
| return `${(num / 1000).toFixed(1)}k`; | ||
| } | ||
| return num; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Handle edge cases for robust number formatting
While the basic implementation works, consider handling these edge cases:
- Negative numbers
- NaN/Infinity values
- Decimal number inputs
export const convertToKUnits = (num: number) => {
+ if (!Number.isFinite(num)) return 'N/A';
+ const absNum = Math.abs(num);
- if (num >= 1000) {
- return `${(num / 1000).toFixed(1)}k`;
+ if (absNum >= 1000) {
+ const sign = num < 0 ? '-' : '';
+ return `${sign}${(absNum / 1000).toFixed(1)}k`;
}
- return num;
+ return num.toString();
};📝 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.
| export const convertToKUnits = (num: number) => { | |
| if (num >= 1000) { | |
| return `${(num / 1000).toFixed(1)}k`; | |
| } | |
| return num; | |
| }; | |
| export const convertToKUnits = (num: number) => { | |
| if (!Number.isFinite(num)) return 'N/A'; | |
| const absNum = Math.abs(num); | |
| if (absNum >= 1000) { | |
| const sign = num < 0 ? '-' : ''; | |
| return `${sign}${(absNum / 1000).toFixed(1)}k`; | |
| } | |
| return num.toString(); | |
| }; |
| import React from "react"; | ||
| import AppLayout from "@/layouts/app-layout"; | ||
| import { stylesFn } from "@/styles/CollaborationHistory.styles"; | ||
| import { useTheme } from "@react-navigation/native"; | ||
| import React, { useState } from "react"; | ||
| import { View, ScrollView, StyleSheet } from "react-native"; | ||
| import { | ||
| TextInput, | ||
| Button, | ||
| Title, | ||
| Paragraph, | ||
| IconButton, | ||
| RadioButton, | ||
| } from "react-native-paper"; | ||
| import ScreenHeader from "@/components/ui/screen-header"; | ||
|
|
There was a problem hiding this comment.
Component name doesn't match the file name
The file is named CollaborationHistory.tsx but exports a component named CreateCollaborationScreen. This naming inconsistency could lead to confusion. Consider renaming either:
- The component to
CollaborationHistoryto match the file name, or - The file to
CreateCollaborationScreen.tsxto match the component name
| return ( | ||
| <AppLayout> | ||
| <ScrollView style={styles.container}> | ||
| <View | ||
| style={{ | ||
| flexDirection: "row", | ||
| alignItems: "center", | ||
| marginBottom: 16, | ||
| gap: 16, | ||
| }} | ||
| > | ||
| <BackButton /> | ||
| <Title style={styles.title}>Collaboration History</Title> | ||
| </View> | ||
| </ScrollView> | ||
| <ScreenHeader | ||
| title="Collaboration History" | ||
| /> | ||
| </AppLayout> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
💡 Codebase verification
Component name inconsistent with its purpose
The component is named CreateCollaborationScreen but it's clearly a history view component based on:
- The rendered title "Collaboration History"
- The file name
CollaborationHistory.tsx - The existence of separate creation-related files (
CreateCollaborationMap.tsxandCreateCollaborationForm.ts)
The component should be renamed to match its purpose:
- Change the component name from
CreateCollaborationScreentoCollaborationHistoryScreen - Update any imports/references accordingly
🔗 Analysis chain
Verify component purpose and functionality
The component name CreateCollaborationScreen suggests creation functionality, but it appears to be a history view based on the title "Collaboration History". This seems contradictory. Please verify:
- Is this meant to be a creation screen or a history view?
- If it's a creation screen, where is the creation functionality?
- If it's a history view, shouldn't the component be renamed?
Let's check for related components and usage:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for related collaboration components and their usage
echo "Searching for collaboration-related components..."
rg -l "Collaboration" --type tsx
echo "\nChecking for references to this component..."
rg "CreateCollaborationScreen" --type tsx
Length of output: 342
Script:
#!/bin/bash
# Search for related collaboration components and their usage with correct file extensions
echo "Searching for collaboration-related files..."
fd -e tsx -e ts "Collaboration"
echo "\nSearching for collaboration-related content..."
rg "Collaboration" -t ts -t tsx
echo "\nChecking component references..."
rg "CreateCollaborationScreen" -t ts -t tsx
Length of output: 919
Script:
#!/bin/bash
# Let's check the content of the file to understand its actual purpose
echo "Checking the full content of CollaborationHistory.tsx..."
cat "app/(main)/(screens)/CollaborationHistory.tsx"
echo "\nChecking create collaboration related files..."
cat "components/collaboration/create-collaboration/CreateCollaborationMap.tsx"
cat "constants/CreateCollaborationForm.ts"
Length of output: 3392
| import { stylesFn } from "@/styles/tag/Tag.styles"; | ||
| import { useTheme } from "@react-navigation/native"; | ||
| import { Chip, ChipProps } from "react-native-paper"; | ||
|
|
||
| const Tag: React.FC<ChipProps> = ({ | ||
| children, | ||
| ...props | ||
| }) => { | ||
| const theme = useTheme(); | ||
| const styles = stylesFn(theme); | ||
|
|
||
| return ( | ||
| <Chip | ||
| style={styles.tag} | ||
| textStyle={styles.tagText} | ||
| {...props} | ||
| > | ||
| {children} | ||
| </Chip> | ||
| ); | ||
| }; | ||
|
|
||
| export default Tag; |
There was a problem hiding this comment.
💡 Codebase verification
Migration from Chip to Tag component is incomplete
The FilterModal.tsx still uses Chip directly from react-native-paper instead of the new Tag component. Found two instances:
- Categories section using
<Chip>for category selection - Job Types section using
<Chip>for job type selection
Both instances should be migrated to use the new Tag component for consistency.
🔗 Analysis chain
Verify complete migration from Chip to Tag
The AI summary mentions this component replacing Chip in CollaborationCard. Let's verify the migration is complete.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for any remaining direct Chip usage that should use Tag instead
rg -l "import.*Chip.*react-native-paper" | \
xargs rg "<Chip" -l | \
grep -v "components/ui/tag/index.tsx"
Length of output: 129
Script:
#!/bin/bash
# Check the usage of Chip in FilterModal.tsx to understand the context
rg -A 5 -B 5 "<Chip" components/FilterModal.tsx
Length of output: 941
| export const imageUrl = (image: string | NodeRequire | undefined) => { | ||
| if ( | ||
| image && | ||
| typeof image === "string" && | ||
| (image.startsWith("http") || image.startsWith("ph://")) | ||
| ) { | ||
| return { | ||
| uri: image, | ||
| }; | ||
| } else if (image) { | ||
| return image; | ||
| } else { | ||
| return require("@/assets/images/placeholder-image.jpg"); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider improving type safety and return type consistency.
The function has inconsistent return types which could lead to type-related issues downstream. Consider using a discriminated union type for the return value.
+type ImageSource =
+ | { type: 'uri'; uri: string }
+ | { type: 'require'; source: NodeRequire };
+
-export const imageUrl = (image: string | NodeRequire | undefined) => {
+export const imageUrl = (image: string | NodeRequire | undefined): ImageSource => {
if (
image &&
typeof image === "string" &&
(image.startsWith("http") || image.startsWith("ph://"))
) {
- return {
- uri: image,
- };
+ return { type: 'uri', uri: image };
} else if (image) {
- return image;
+ return { type: 'require', source: image as NodeRequire };
} else {
- return require("@/assets/images/placeholder-image.jpg");
+ return { type: 'require', source: require("@/assets/images/placeholder-image.jpg") };
}
};📝 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.
| export const imageUrl = (image: string | NodeRequire | undefined) => { | |
| if ( | |
| image && | |
| typeof image === "string" && | |
| (image.startsWith("http") || image.startsWith("ph://")) | |
| ) { | |
| return { | |
| uri: image, | |
| }; | |
| } else if (image) { | |
| return image; | |
| } else { | |
| return require("@/assets/images/placeholder-image.jpg"); | |
| } | |
| }; | |
| type ImageSource = | |
| | { type: 'uri'; uri: string } | |
| | { type: 'require'; source: NodeRequire }; | |
| export const imageUrl = (image: string | NodeRequire | undefined): ImageSource => { | |
| if ( | |
| image && | |
| typeof image === "string" && | |
| (image.startsWith("http") || image.startsWith("ph://")) | |
| ) { | |
| return { type: 'uri', uri: image }; | |
| } else if (image) { | |
| return { type: 'require', source: image as NodeRequire }; | |
| } else { | |
| return { type: 'require', source: require("@/assets/images/placeholder-image.jpg") }; | |
| } | |
| }; |
| const onImagePress = (data: any) => { | ||
| setSelectedImage(data); // TODO: data -> uri | ||
| setIsZoomed(true); | ||
| } |
There was a problem hiding this comment.
Resolve the TODO in onImagePress function
The onImagePress function contains a TODO comment indicating that data should be converted to uri. This suggests that data may not be in the correct format, which could lead to issues when displaying the zoomed image. Please ensure that data contains the correct image URI or extract the uri property before setting selectedImage.
Apply this diff to address the issue:
const onImagePress = (data: any) => {
- setSelectedImage(data); // TODO: data -> uri
+ setSelectedImage(data.uri);
setIsZoomed(true);
}| useEffect(() => { | ||
| if (props?.alreadyInvited) { | ||
| props.alreadyInvited(props.influencer.id).then((invited) => { | ||
| setIsInvited(invited); | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| 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)} | ||
| /> | ||
| ); | ||
| } | ||
| }; | ||
| }, []); |
There was a problem hiding this comment.
Include dependencies in the useEffect hook
The useEffect hook has an empty dependency array [], but it relies on props.alreadyInvited and props.influencer.id. If these props change, the effect won't re-run, and isInvited may not update accordingly. To ensure the invitation status reflects the current props, include them in the dependency array.
Apply this diff:
useEffect(() => {
if (props?.alreadyInvited) {
props.alreadyInvited(props.influencer.id).then((invited) => {
setIsInvited(invited);
});
}
- }, []);
+ }, [props.alreadyInvited, props.influencer.id]);📝 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.
| useEffect(() => { | |
| if (props?.alreadyInvited) { | |
| props.alreadyInvited(props.influencer.id).then((invited) => { | |
| setIsInvited(invited); | |
| }); | |
| } | |
| }; | |
| 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)} | |
| /> | |
| ); | |
| } | |
| }; | |
| }, []); | |
| useEffect(() => { | |
| if (props?.alreadyInvited) { | |
| props.alreadyInvited(props.influencer.id).then((invited) => { | |
| setIsInvited(invited); | |
| }); | |
| } | |
| }, [props.alreadyInvited, props.influencer.id]); |
| <TouchableOpacity | ||
| onPress={() => { | ||
| return router.push("/(main)/CollaborationHistory"); | ||
| }} | ||
| > | ||
| <Text style={styles.jobHistory}> | ||
| {influencer.jobsCompleted} Jobs completed ({influencer.successRate}{" "} | ||
| success rate) | ||
| </Text> | ||
| </TouchableOpacity> |
There was a problem hiding this comment.
Pass influencer ID when navigating to collaboration history
When navigating to the CollaborationHistory screen, the influencer's ID should be included to display the correct data. Modify the route to pass the influencer's ID dynamically.
Apply this diff:
<TouchableOpacity
onPress={() => {
- return router.push("/(main)/CollaborationHistory");
+ return router.push(`/collaboration-history/${influencer.id}`);
}}
>
<Text style={styles.jobHistory}>
{influencer.jobsCompleted} Jobs completed ({influencer.successRate}{" "}
success rate)
</Text>
</TouchableOpacity>Ensure that the route /collaboration-history/[id] exists and is configured to handle the influencer ID.
Committable suggestion skipped: line range outside the PR's diff.
| promotionType: promotionType[0].value, | ||
| collaborationType: collabType[0].value, | ||
| numberOfInfluencersNeeded: numInfluencers, | ||
| platform, | ||
| platform: platform[0].value, |
There was a problem hiding this comment.
Potential Runtime Error When Accessing Array Elements Without Checks
In the submitCollaboration function, you access promotionType[0].value, collabType[0].value, and platform[0].value without verifying that these arrays have at least one element. If any of these arrays are empty, this will cause a runtime error.
Ensure that these arrays are not empty before accessing their elements. Consider adding checks:
if (
!collaborationName ||
!aboutCollab ||
!budgetMin ||
!budgetMax ||
!promotionType ||
!collabType ||
!numInfluencers ||
!platform ||
!location
) {
Toaster.error("Please fill all fields");
return;
}
+if (
+ promotionType.length === 0 ||
+ collabType.length === 0 ||
+ platform.length === 0
+) {
+ Toaster.error("Please select at least one option for Promotion Type, Collaboration Type, and Platform");
+ return;
+}Also, before accessing the first element, you can add:
const promotionTypeValue = promotionType.length > 0 ? promotionType[0].value : null;Repeat similar checks for collabType and platform.
| const [promotionType, setPromotionType] = useState<SelectItem[]>([]); | ||
| const [collabType, setCollabType] = useState<SelectItem[]>([]); | ||
| const [platform, setPlatform] = useState([ | ||
| { | ||
| label: "Instagram", | ||
| value: "Instagram", | ||
| }, | ||
| ]); |
There was a problem hiding this comment.
Potential Runtime Error When Accessing Elements in Empty Arrays
The state variables promotionType, collabType, and platform are initialized as arrays. Later in your code, you access their first elements without checking if they contain any items. If these arrays are empty, accessing promotionType[0].value will result in a runtime error.
To prevent this, ensure that these arrays are not empty before accessing their elements. You can initialize them with default values or add checks before accessing:
-const [promotionType, setPromotionType] = useState<SelectItem[]>([]);
+const [promotionType, setPromotionType] = useState<SelectItem[]>([PROMOTION_TYPES[0]]);
-const [collabType, setCollabType] = useState<SelectItem[]>([]);
+const [collabType, setCollabType] = useState<SelectItem[]>([COLLAB_TYPES[0]]);
-const [platform, setPlatform] = useState([
- {
- label: "Instagram",
- value: "Instagram",
- },
-]);
+const [platform, setPlatform] = useState([PLATFORM_TYPES[0]]);Alternatively, modify your validation to ensure these arrays have at least one item before accessing them.
Committable suggestion skipped: line range outside the PR's diff.
Summary by CodeRabbit
Release Notes
New Features
Selectcomponent for item selection with multi-selection support.CollaborationHeaderandOverviewTabContentcomponents for improved collaboration details display.CarouselNativecomponent for enhanced media display.User Interface Enhancements
EmptyStatecomponent for better user feedback when no data is available.Bug Fixes
Chores
package.jsonto include Font Awesome icons.