Repository navigation
Feedbacks Resolved: 3 - #41
Conversation
* feedbacks resolved
* carousel for web changes * crash scenario * drawer ui improvement
* theme updated and code refactoring
* initial implementation * updateBytes function added * made changes for processed and raw attachments
* feedbacks * resolved feedbacks * feedbacks * create collaboration icons * feedbacks * empty state for messages screen
* feedbacks resolved
WalkthroughThe pull request introduces significant modifications across various components within the application. Key changes include updates to tab icons and titles in the Changes
Possibly related PRs
Suggested reviewers
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.
Caution
Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.
Actionable comments posted: 22
🧹 Outside diff range and nitpick comments (49)
components/proposals/Invitations.tsx (2)
Line range hint
52-91: Consider enhancing error handling and type safetyThe fetchProposals function could benefit from:
- User-facing error notifications instead of just console.error
- TypeScript interfaces for the proposal data structure
- Error boundary implementation for better error recovery
Would you like me to provide an example implementation with these improvements?
Line range hint
147-153: Fix typo in empty state messageThe empty state subtitle contains a typo: "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"components/collaboration/collaboration-details/OverviewTabContent.tsx (2)
34-35: Consider enhancing the responsive layout implementationWhile the current implementation works, it could be improved for better maintainability and user experience:
- Move the magic number
768to a constant or theme variable- Consider using
maxWidthinstead of fixedwidthto handle edge cases better- Add a smooth transition to prevent jarring layout shifts
Consider applying this improvement:
+ // At the top of the file with other constants + const MAX_CONTENT_WIDTH = 768; <ScrollView style={{ flex: 1, paddingTop: 8, paddingHorizontal: 16, paddingBottom: 16, - width: xl ? 768 : '100%', + maxWidth: MAX_CONTENT_WIDTH, marginHorizontal: "auto", + transition: 'width 0.3s ease', // Add smooth transition }}
Line range hint
1-108: Consider architectural improvements for better maintainabilitySeveral improvements could enhance the component's maintainability and reliability:
- Extract repeated Card sections into a reusable component
- Remove hardcoded values (e.g., "Instagram" platform)
- Add proper error handling for missing collaboration data
- Remove unnecessary string concatenation with spaces
Here's a suggested approach for extracting the card component:
interface InfoCardProps { title: string; content: React.ReactNode; image?: string; } const InfoCard: React.FC<InfoCardProps> = ({ title, content, image }) => ( <Card style={styles.infoCard}> {image && <Image source={{ uri: image }} style={styles.profileImage} />} <View> <Text variant="headlineSmall" style={styles.cardName}>{title}</Text> </View> <Card.Content>{content}</Card.Content> </Card> ); // Usage in main component: <InfoCard title="Platform" content={<Paragraph style={styles.paragraph}>{collaboration.platform}</Paragraph>} />Also, consider adding null checks:
- Cost: {collaboration.budget.min} + Cost: {collaboration?.budget?.min ?? 'N/A'}components/drawer-layout/BrandActionItem.tsx (1)
50-57: Consider these refinements for better maintainabilityThe FontAwesome implementation looks good, but there are a few potential improvements:
- Move the margin style to the styles object:
-style={{ - marginRight: 6, - backgroundColor: Colors(theme).transparent, -}} +style={[ + styles.icon, + { backgroundColor: Colors(theme).transparent } +]}Add to stylesFn:
icon: { marginRight: 6, }
- Simplify the color prop using a ternary:
-color={active ? Colors(theme).white : Colors(theme).text} +color={Colors(theme)[active ? 'white' : 'text']}Also applies to: 74-77
components/explore-influencers/header.tsx (2)
12-18: Remove unused props parameter and consider modern TypeScript practicesThe component declares props but doesn't use them. Also, the
React.FCtype annotation is redundant with modern TypeScript.-const Header: React.FC = (props) => { +const Header = () => {
21-36: Consider extracting styles for better maintainabilityThe inline styles could be moved to a separate styles object or a styled-components implementation for better reusability and maintainability.
+const styles = { + container: { + display: "flex", + flexDirection: "row", + alignItems: "center", + }, + brandText: { + fontSize: 24, + fontWeight: "bold", + } +}; -<View - style={{ - display: "flex", - flexDirection: "row", - alignItems: "center", - }} -> +<View style={styles.container}> <Text - style={{ - color: Colors(theme).text, - fontSize: 24, - fontWeight: "bold", - }} + style={[styles.brandText, { color: Colors(theme).text }]} >components/explore-influencers/index.tsx (2)
93-94: Document theme-dependent padding behaviorThe padding changes based on both breakpoint and theme. Consider adding a comment explaining why dark theme requires additional padding.
style={{ paddingHorizontal: xl ? 0 : 16, + // Additional padding needed in dark theme to separate search component from content paddingBottom: theme.dark ? 16 : 0, }}
103-106: Extract magic number to constantsThe fixed width value (768) should be moved to a constants file for better maintainability.
+// In constants/Layout.ts +export const CONTENT_MAX_WIDTH = 768; -style={{ - width: xl ? 768 : '100%', - marginHorizontal: "auto", -}} +style={{ + width: xl ? CONTENT_MAX_WIDTH : '100%', + marginHorizontal: "auto", +}}components/collaboration/collaboration-details/ApplicationsTabContent.tsx (2)
15-15: Consider using TypeScript properly for better type safetyThe
useBreakpointshook implementation looks good, but the component props are typed asany. Consider defining proper interface for the props.interface ApplicationsTabContentProps { pageID: string; collaboration: { // Add relevant collaboration properties }; }Also applies to: 24-26
126-127: Consider extracting magic numbers into constantsThe hardcoded width value of 768 should be extracted into a constant or theme variable for better maintainability.
+ const DESKTOP_WIDTH = 768; // ... - width: xl ? 768 : '100%', + width: xl ? DESKTOP_WIDTH : '100%',components/collaboration/collaboration-details/InvitationsTabContent.tsx (2)
Line range hint
52-75: Improve error handling in handleCollaborationInviteThe current error handling only logs to console and shows a generic message. Consider handling specific error cases.
try { // ... existing code ... } catch (error) { - console.error(error); - Toaster.error("Failed to send invitation"); + if (error instanceof Error) { + console.error('Invitation error:', error.message); + Toaster.error( + error.message.includes('permission-denied') + ? "You don't have permission to send invitations" + : "Failed to send invitation" + ); + } }
Line range hint
178-220: Consider extracting the invitation modal into a separate componentThe modal logic and UI could be moved to a separate component to improve maintainability and reusability.
interface InvitationModalProps { visible: boolean; onClose: () => void; onSubmit: (message: string) => Promise<void>; isLoading: boolean; } const InvitationModal: React.FC<InvitationModalProps> = ({ visible, onClose, onSubmit, isLoading, }) => { // ... modal implementation };components/proposals/Applications.tsx (2)
Line range hint
54-121: Consider extracting data fetching logic into a custom hookThe proposal fetching logic is complex and could be reused. Consider moving it to a custom hook.
const useProposals = (brandId: string) => { const [proposals, setProposals] = useState<Proposal[]>([]); const [isLoading, setIsLoading] = useState(true); const fetchProposals = useCallback(async () => { // ... existing fetch logic }, [brandId]); useEffect(() => { fetchProposals(); }, [fetchProposals]); return { proposals, isLoading, refetch: fetchProposals }; };
Line range hint
164-186: Consider reducing prop drilling in JobCardThe JobCard component receives many individual props. Consider passing a structured object instead.
interface JobCardProps { collaboration: { name: string; id: string; brandName: string; // ... other properties }; onOpenBottomSheet: (id: string) => void; }components/create-collaboration/screen-two.tsx (1)
126-126: Avoid using index as a key when rendering listsUsing the index as part of the key can cause issues if the list items change order or are modified. It's better to use a unique identifier from the data.
Update the key to use a unique property like
link.url:- <Paragraph key={index + link.url}> + <Paragraph key={link.url}>styles/searchbar/Searchbar.styles.tsx (1)
6-12: Consider adding accessibility-friendly dimensionsWhile the current dimensions work, consider adjusting the height to meet minimum touch target sizes for better accessibility:
- Minimum height should be 44px for touch targets
- Consider adding proper padding for better touch areas
searchbar: { flex: 1, fontSize: 16, borderRadius: 10, - height: 40, + height: 44, + paddingHorizontal: 12, backgroundColor: Colors(theme).aliceBlue, },components/ui/button/index.tsx (2)
7-9: Enhance type safety for animated stylesThe
customStylestype could be more specific to ensure proper animated values are passed.interface ButtonProps extends RNPButtonProps { - customStyles?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>; + customStyles?: Animated.AnimatedProps<StyleProp<ViewStyle>> | StyleProp<ViewStyle>; }
11-24: Consider making the button mode configurableThe button mode is hardcoded to "contained". Consider making it configurable while keeping "contained" as the default.
const Button: React.FC<ButtonProps> = ({ customStyles, + mode = "contained", ...props }) => { return ( <RNPButton - mode="contained" + mode={mode} style={[customStyles]} {...props} /> ); };components/drawer-layout/DrawerIcon.tsx (3)
7-10: Consider extending props interfaceThe interface could be more flexible by adding a size prop with a default value.
interface DrawerIconProps { href?: string; icon: IconProp; + size?: number; }
22-26: Improve color logic maintainabilityThe color logic could be simplified and made more maintainable.
- color={ - href?.includes(pathname) - ? Colors(theme).white - : Colors(theme).text - } + color={Colors(theme)[href?.includes(pathname) ? 'white' : 'text']}
27-27: Consider making icon size configurableThe hardcoded size of 28 should be made configurable with a default value.
- size={28} + size={size ?? 28}styles/button/Button.styles.tsx (1)
14-21: Consider platform-specific shadow implementationsThe current shadow implementation might render differently across platforms. Consider using platform-specific shadow implementations for consistent appearance.
shadowColor: Colors(theme).black, -shadowOffset: { - width: 0, - height: 2, -}, -shadowOpacity: 0.25, -shadowRadius: 3.84, -elevation: 5, +...Platform.select({ + ios: { + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.25, + shadowRadius: 3.84, + }, + android: { + elevation: 5, + }, +}),styles/modal/AddModal.styles.tsx (1)
Line range hint
26-35: Consider adding accessibility propertiesFor better accessibility, consider adding
accessibilityRoleandaccessibilityLabelstyles to complement the modal title styling.modalTitle: { paddingTop: 15, textAlign: "center", fontSize: 20, fontWeight: "bold", color: Colors(theme).gray100, + accessibilityRole: "header", },components/ui/back-button/BackButton.tsx (1)
Line range hint
20-42: Remove redundant Pressable wrapperThe component has nested
Pressablecomponents with the sameonPresshandler, which is unnecessary and could lead to event bubbling.Suggested fix:
return ( <Pressable onPress={() => navigation.goBack()} + style={{ + display: "flex", + justifyContent: "center", + alignItems: "center", + }} > - <View - style={{ - display: "flex", - justifyContent: "center", - alignItems: "center", - }} - > - <Pressable - onPress={() => navigation.goBack()} - > - {({ pressed }) => ( <FontAwesomeIcon icon={faArrowLeft} size={20} color={color ?? Colors(theme).text} style={{ opacity: pressed ? 0.8 : 1, }} /> - )} - </Pressable> - </View> </Pressable> );styles/tab1.styles.tsx (1)
15-15: Consider extracting style constantsCommon values like spacing and font sizes should be extracted to a constants file for better maintainability and consistency.
Create a new file
constants/Layout.ts:export const spacing = { xs: 8, sm: 16, md: 20, lg: 24, xl: 30, }; export const typography = { title: 24, body: 16, };Then update the styles:
- paddingHorizontal: 16, + paddingHorizontal: spacing.sm, - fontSize: 24, + fontSize: typography.title, - fontSize: 16, + fontSize: typography.body,Also applies to: 39-39
components/create-collaboration/screen-three.tsx (1)
22-35: Consider adding accessibility attributes.While the implementation looks good, consider enhancing accessibility for screen readers.
<View style={styles.container3}> <FontAwesomeIcon icon={faCheckCircle} size={100} color={Colors(theme).primary} style={styles.checkIcon} + accessibilityRole="image" + accessibilityLabel="Success check mark" /> <Title style={styles.title} + accessibilityRole="header" > Collaboration {type === "Add" ? "Posted" : "Updated"} </Title> <Text style={styles.description} + accessibilityRole="text" > Your collaboration has been successfully {type === "Add" ? "posted" : "updated"}. </Text> </View>constants/Colors.ts (1)
Line range hint
1-58: Consider documenting color semantic usage.The color system is growing. Consider adding JSDoc comments to document the semantic usage of each color token.
export default (theme: Theme) => ({ ...theme.colors, ...(theme.dark ? { + /** Used for card backgrounds in dark mode */ card: "#1E1E1E", + /** Used for component outlines and borders */ outline: "#538BA6", // ... add similar documentation for other colorscomponents/drawer-layout/DrawerMenuItem.tsx (1)
44-48: Consider memoizing icon rendering for performanceThe icon rendering could benefit from memoization to prevent unnecessary re-renders.
+ const iconElement = React.useMemo(() => + tab.icon({ + focused: tab.href.includes(pathname), + }), + [tab.icon, pathname] + ); return ( <Pressable onPress={() => router.push(tab.href)}> <View style={{...}}> - {tab.icon({ - focused: tab.href.includes(pathname), - })} + {iconElement}components/ui/screen-header/index.tsx (3)
Line range hint
27-33: Memoize handleAction functionThe
handleActionfunction is recreated on every render but its dependencies are stable.- const handleAction = () => { + const handleAction = React.useCallback(() => { if (action) { action(); } else { navigation.goBack(); } - } + }, [action, navigation]);
73-73: Simplify rightAction rendering conditionThe current condition could be simplified and made more explicit.
- {rightAction && rightActionButton} + {rightActionButton && rightAction ? rightActionButton : null}
43-65: Extract icon styles to constantsConsider extracting the repeated style objects to constants for better maintainability.
+ const styles = { + iconContainer: { + marginTop: 2, + }, + icon: { + size: 20, + }, + }; {!hideAction && ( <Appbar.Action icon={() => ( <View - style={{ - marginTop: 2, - }} + style={styles.iconContainer} lightColor={Colors(theme).transparent} darkColor={Colors(theme).transparent} > <FontAwesomeIcon icon={faArrowLeft} - size={20} + size={styles.icon.size} color={Colors(theme).text} /> </View> )} color={Colors(theme).text} onPress={handleAction} /> )}components/ui/brand-switcher/index.tsx (1)
Line range hint
42-48: Optimize icon styling propertiesWhile the icon change to
faChevronDownis a good choice for dropdown indication, there's redundancy in the color definition:<FontAwesomeIcon - color={Colors(theme).text} icon={faChevronDown} size={24} style={{ marginLeft: 14, - color: Colors(theme).text, marginBottom: -2, }} />Also, consider using proper vertical alignment instead of negative margin:
style={{ marginLeft: 14, - marginBottom: -2, + alignSelf: 'center' }}contexts/collaboration-context.provider.tsx (2)
16-21: Consider implementing data validation and sanitizationThe interface implementation should include input validation before storage:
Consider implementing a validation layer:
- Create a validation schema for
ICollaboration- Add input sanitization
- Implement type guards
Example implementation:
import { z } from 'zod'; const CollaborationSchema = z.object({ // define your schema here }); function validateCollaboration(data: unknown): ICollaboration { return CollaborationSchema.parse(data); }
62-63: Consider implementing optimistic updatesThe context could benefit from optimistic updates to improve UX:
- Update local state immediately
- Revert on error
- Implement proper loading states
This would make the UI feel more responsive while maintaining data integrity.
components/SearchComponent.tsx (1)
38-44: Consider memoizing the icon render functionThe icon render function is recreated on every render. Consider memoizing it using
useCallbackto optimize performance.+ const renderSearchIcon = useCallback(() => ( + <FontAwesomeIcon + color={Colors(theme).gray100} + icon={faMagnifyingGlass} + size={18} + /> + ), [theme]); return ( <View style={[searchComponentStyles.searchContainer]}> <Searchbar - icon={() => ( - <FontAwesomeIcon - color={Colors(theme).gray100} - icon={faMagnifyingGlass} - size={18} - /> - )} + icon={renderSearchIcon}components/channel/channel.tsx (1)
49-60: Consider extracting the add member button to a separate componentThe add member button logic could be extracted to improve readability and reusability. Also, consider adding accessibility attributes.
+ const AddMemberButton: React.FC<{ onPress: () => void }> = ({ onPress }) => { + const theme = useTheme(); + return ( + <Pressable + onPress={onPress} + accessibilityRole="button" + accessibilityLabel="Add member" + > + <FontAwesomeIcon + icon={faPlus} + size={20} + color={Colors(theme).text} + /> + </Pressable> + ); + }; <ScreenHeader title={channel?.data?.name || 'Chat'} rightAction - rightActionButton={ - <Pressable - onPress={() => setModalVisible(true)} - > - <FontAwesomeIcon - icon={faPlus} - size={20} - color={Colors(theme).text} - /> - </Pressable> - } + rightActionButton={ + <AddMemberButton onPress={() => setModalVisible(true)} /> + } />components/collaboration/CollaborationHeader.tsx (1)
48-54: Consider optimizing icon render functionsWhile the FontAwesome icon implementation looks good, we can optimize performance by memoizing the icon render functions or moving them outside the component to prevent unnecessary re-renders.
Consider this optimization:
+ const renderBoltIcon = (theme: Theme) => ( + <FontAwesomeIcon + color={Colors(theme).primary} + icon={faBolt} + size={14} + /> + ); + const renderEyeIcon = (theme: Theme) => ( + <FontAwesomeIcon + color={Colors(theme).primary} + icon={faEye} + size={14} + /> + ); + const renderLocationIcon = (theme: Theme) => ( + <FontAwesomeIcon + color={Colors(theme).primary} + icon={faLocationDot} + size={14} + /> + ); const CollaborationHeader: React.FC<ColloborationHeaderProps> = ({ collaboration, }) => { const theme = useTheme(); const styles = stylesFn(theme); return ( // ... - icon={() => ( - <FontAwesomeIcon - color={Colors(theme).primary} - icon={faBolt} - size={14} - /> - )} + icon={() => renderBoltIcon(theme)} // ... Apply similar changes for other icons ); };Also applies to: 63-69, 76-82
components/ui/carousel/render-media-item.tsx (1)
42-42: LGTM: Loading state management for imagesThe addition of loading state and ActivityIndicator improves user experience by providing visual feedback during image loading.
Consider adding error handling:
<Image source={imageUrl(item.url)} style={[styles.media, ...]} resizeMode="stretch" onLoadStart={() => setIsLoading(true)} onLoad={() => setIsLoading(false)} + onError={() => { + setIsLoading(false); + console.error('Image loading failed:', item.url); + }} />Also applies to: 58-67, 78-79
components/ui/modal/ImageUploadModal.tsx (1)
Line range hint
27-45: Consider sharing permission handling logicThe permission handling logic here is well implemented. Consider extracting it into a shared utility to maintain consistency across both upload modals.
Create a shared utility:
// utils/permissions.ts export const requestMediaPermission = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { Alert.alert( 'Permission Required', 'Please grant permissions from settings', [ { text: 'Cancel', style: 'cancel' }, { text: 'Open Settings', onPress: () => Linking.openSettings() }, ] ); return false; } return true; };components/ui/select/index.tsx (1)
56-70: Consider extracting style objectsThe inline styles could be moved outside the component for better readability and performance.
+const getContainerStyle = (direction: "row" | "column") => ({ + flex: 1, + gap: 8, + ...(direction === "row" + ? { flexDirection: "row", flexWrap: "wrap" } + : { flexDirection: "column", justifyContent: "center" }) +}); return ( <View style={[ - { - flex: 1, - gap: 8, - }, - direction === "row" ? { - flexDirection: "row", - flexWrap: "wrap", - } : { - flexDirection: "column", - justifyContent: "center", - }, + getContainerStyle(direction), style, ]} >app/(public)/pre-signin.tsx (2)
Line range hint
25-35: Consider memoizing the skipToConnect functionThe
skipToConnectfunction could be memoized since it depends only on the staticslidesarray.+import { useCallback } from 'react'; -const skipToConnect = () => { +const skipToConnect = useCallback(() => { const connectSlideIndex = slides.findIndex( (slide) => slide.key === "connect" ); if (connectSlideIndex !== -1) { swiperRef.current?.scrollBy(connectSlideIndex); } -}; +}, []);
97-97: Enhance error handling presentationThe error message could benefit from a more structured presentation using a dedicated error component.
-{error && <Text style={{ color: "red" }}>Error: {error}</Text>} +{error && ( + <View style={styles.errorContainer}> + <Text style={styles.errorText}>Error: {error}</Text> + </View> +)}components/channel/channel-list.tsx (1)
82-98: Consider adding loading state handlingWhile the empty state implementation looks good, consider handling the loading state to prevent flashing of the empty state during initial data fetch.
<ChannelList + LoadingIndicator={() => ( + <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> + <ActivityIndicator size="large" color={Colors(theme).primary} /> + </View> + )} EmptyStateIndicator={() => ( // ... existing code )}components/menu/index.tsx (1)
114-119: Add hover and active states for better interaction feedbackThe chevron icon could benefit from hover and active states for better user interaction feedback.
<Pressable + style={({ pressed }) => [ + styles.userProfileContainer, + pressed && { opacity: 0.7 } + ]} onPress={() => { router.push("/profile"); }} >app/(main)/(drawer)/(tabs)/_layout.tsx (1)
53-73: Consider memoizing the header componentThe header component is recreated on each render. Consider memoizing it for better performance.
+ const MemoizedHeader = React.memo(Header); + const TabLayout = () => { // ... existing code headerTitle() { return ( - <Header /> + <MemoizedHeader /> ) },components/drawer-layout/DrawerMenuContent.tsx (1)
34-35: Simplify empty interface declarationThe empty interface can be simplified to a type alias.
-interface DrawerMenuContentProps { } +type DrawerMenuContentProps = Record<string, never>;🧰 Tools
🪛 Biome (1.9.4)
[error] 34-35: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
components/create-collaboration/screen-one.tsx (1)
84-84: Remove commented codeRemove the commented
multilineprop or implement it if needed for better user input experience.components/BottomSheetActions.tsx (1)
Line range hint
19-26: Consider improving type safety for cardIdThe
cardIdprop is currently typed asany, which could lead to runtime errors. Consider creating a proper type definition.interface BottomSheetActionsProps { cardType: | "influencerType" | "promotionType" | "influencerCard" | "applicationCard" | "invitationCard" | "activeCollab"; data?: any; // TODO: Update with the correct type - cardId?: any; + cardId?: string | { collaborationID: string; applicationID: string; influencerID: string }; isVisible: boolean; snapPointsRange: [string, string]; onClose: () => void; }
🛑 Comments failed to post (22)
components/drawer-layout/BrandActionItem.tsx (1)
6-8: 💡 Codebase verification
Mixed icon library usage detected in onboarding screens
The migration to FontAwesome icons is mostly consistent across the codebase, but there are three instances in the onboarding flow that still use react-native-paper's IconButton with icon names:
app/(onboarding)/onboarding-your-brand.tsx: UsesIconButtonwith "arrow-left" iconapp/(onboarding)/onboarding-brand-preference.tsx: UsesIconButtonwith "information-outline" icon in two placesThese should be migrated to FontAwesome icons for consistency with the rest of the application.
🔗 Analysis chain
Verify consistent icon library usage across the codebase
The migration from react-native-paper icons to FontAwesome icons looks good and provides better type safety with
IconProp. However, we should ensure this change is consistent across all components.Also applies to: 12-12
Let me analyze the results. I can see that:
- There are no
Avatar.Iconusages in the codebase- There are only two files still using
IconButtonfrom react-native-paper, both in the onboarding flow- FontAwesomeIcon is widely used across the codebase (29 files)
Let me verify if the IconButton usage in those onboarding files actually uses icons:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for mixed usage of icon libraries # Look for components still using react-native-paper icons # Check for Avatar.Icon usage rg "Avatar\.Icon" # Check for IconButton usage from react-native-paper rg "IconButton.*from.*react-native-paper" # Check for consistent FontAwesome imports rg "import.*FontAwesomeIcon"Length of output: 3595
Script:
#!/bin/bash # Check the context of IconButton usage in onboarding files rg -B 2 -A 2 "IconButton" "app/(onboarding)/onboarding-brand-preference.tsx" "app/(onboarding)/onboarding-your-brand.tsx"Length of output: 2345
components/explore-influencers/header.tsx (1)
37-57:
⚠️ Potential issueAdd onPress handler and improve icon positioning
The Pressable component lacks an onPress handler, and the icon positioning uses fragile negative margins.
-<Pressable> +<Pressable onPress={() => xl ? undefined : toggleDrawer()}> { xl ? ( <BrandSwitcher /> ) : ( <DrawerToggleButton icon={ <FontAwesomeIcon color={Colors(theme).text} icon={faChevronDown} size={16} style={{ - marginLeft: 6, - marginBottom: -2, + marginLeft: 6, + transform: [{ translateY: 1 }] }} /> } /> ) } </Pressable>Committable suggestion skipped: line range outside the PR's diff.
components/create-collaboration/screen-two.tsx (1)
17-17: 🛠️ Refactor suggestion
Define a specific type for the
linksarrayUsing
any[]for thelinksarray can lead to type safety issues. Defining a specific interface for the links enhances type safety and code maintainability.For example, define a
Linkinterface:interface Link { name: string; url: string; }Then update the types:
// In ScreenTwoProps (line 17) - links: any[]; + links: Link[]; // In setState (line 29) - links: React.Dispatch<React.SetStateAction<any[]>>; + links: React.Dispatch<React.SetStateAction<Link[]>>;Also applies to: 29-29
components/create-collaboration/index.tsx (2)
147-149:
⚠️ Potential issuePrevent execution when the user is not authenticated
After logging "User not logged in", the function should return to prevent further execution, which could lead to errors or unintended behavior.
Apply this diff to fix the issue:
if (!AuthApp.currentUser) { console.error("User not logged in"); + return; }📝 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.if (!AuthApp.currentUser) { console.error("User not logged in"); return; }
151-160:
⚠️ Potential issueEnsure selection arrays are not empty
When validating required fields, check that
promotionType,collabType, andplatformarrays are not empty to confirm that selections have been made.Update the validation logic:
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 options for Promotion Type, Collaboration Type, and Platform"); + return; + }📝 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.if ( !collaborationName || !aboutCollab || !budgetMin || !budgetMax || !numInfluencers || !location ) { Toaster.error("Please fill all fields"); return; } if ( promotionType.length === 0 || collabType.length === 0 || platform.length === 0 ) { Toaster.error("Please select options for Promotion Type, Collaboration Type, and Platform"); return; }components/ui/button/index.tsx (1)
18-20: 🛠️ Refactor suggestion
Consider adding base styles and handling style precedence
The style array only includes
customStyleswithout any base styles. Also, spreading props after style could lead to style overrides.<RNPButton mode="contained" style={[ + styles.base, customStyles, + props.style, ]} - {...props} + {...omit(props, ['style'])} />Consider creating a base style object and using a utility like
omitto prevent style prop conflicts.Committable suggestion skipped: line range outside the PR's diff.
components/ui/button/social-button.tsx (2)
9-13: 🛠️ Refactor suggestion
Add loading state and accessibility props
For social authentication buttons, it's important to handle loading states and provide proper accessibility support.
Extend the props interface:
interface SocialButtonProps extends PressableProps { customStyles?: StyleProp<ViewStyle>; icon: IconProp; label: string; + loading?: boolean; + accessibilityLabel?: string; }📝 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.interface SocialButtonProps extends PressableProps { customStyles?: StyleProp<ViewStyle>; icon: IconProp; label: string; loading?: boolean; accessibilityLabel?: string; }
24-39: 🛠️ Refactor suggestion
Enhance button accessibility and loading state handling
The button should handle loading states and provide proper accessibility information.
Suggested implementation:
return ( <Pressable style={[ styles.socialButton, customStyles, ]} + disabled={loading} + accessibilityRole="button" + accessibilityLabel={accessibilityLabel || `Sign in with ${label}`} + accessibilityState={{ disabled: loading }} {...props} > + {loading ? ( + <ActivityIndicator size="small" color={Colors(theme).text} /> + ) : ( <FontAwesomeIcon icon={icon} size={24} color={Colors(theme).text} style={styles.socialButtonIcon} /> + )} <Text style={styles.socialButtonText}>{label}</Text> </Pressable> );Committable suggestion skipped: line range outside the PR's diff.
components/ui/drawer-toggle-button/DrawerToggleButton.tsx (1)
35-42: 🛠️ Refactor suggestion
Ensure adequate touch target size for accessibility.
While the icon implementation looks good, the touch target might be too small for comfortable interaction.
<FontAwesomeIcon color={Colors(theme).text} icon={faBars} size={24} style={{ marginLeft: 14, - marginBottom: -2, + padding: 8, // Add padding to increase touch target }} + accessibilityRole="button" + accessibilityLabel="Open drawer menu" />📝 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.<FontAwesomeIcon color={Colors(theme).text} icon={faBars} size={24} style={{ marginLeft: 14, padding: 8, }} accessibilityRole="button" accessibilityLabel="Open drawer menu"components/explore-influencers/profile-icon.tsx (2)
42-49:
⚠️ Potential issueAdd error handling for image loading
The image source doesn't handle potential null/undefined cases from
selectedBrand?.image, which could lead to runtime errors.+ const imageSource = React.useMemo(() => { + if (!selectedBrand?.image) { + return require('@/assets/images/default-profile.png'); + } + return imageUrl(selectedBrand.image); + }, [selectedBrand?.image]); <Image - source={imageUrl(selectedBrand?.image)} + source={imageSource} + onError={(e) => console.warn('Profile image loading failed:', e.nativeEvent.error)} style={{ borderRadius: 100, height: 28, width: 28, }} />📝 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.const imageSource = React.useMemo(() => { if (!selectedBrand?.image) { return require('@/assets/images/default-profile.png'); } return imageUrl(selectedBrand.image); }, [selectedBrand?.image]); <Image source={imageSource} onError={(e) => console.warn('Profile image loading failed:', e.nativeEvent.error)} style={{ borderRadius: 100, height: 28, width: 28, }} />
19-52: 🛠️ Refactor suggestion
Add accessibility support
The profile icon button lacks accessibility props, making it difficult for screen readers.
<Link href="/menu" asChild> - <Pressable> + <Pressable + accessible={true} + accessibilityRole="button" + accessibilityLabel="Open menu" + accessibilityHint="Opens the profile menu">📝 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.<Link href="/menu" asChild> <Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Open menu" accessibilityHint="Opens the profile menu"> {({ pressed }) => ( <View style={{ position: "relative", marginRight: 15, justifyContent: "center", alignItems: "center", }} > <FontAwesomeIcon color={Colors(theme).primary} icon={faCircleNotch} size={32} style={{ left: -2, opacity: pressed ? 0.5 : 1, position: "absolute", top: -2, zIndex: 1, }} /> <Image source={imageUrl(selectedBrand?.image)} style={{ borderRadius: 100, height: 28, width: 28, }} /> </View> )} </Pressable>components/channel/add-modal.tsx (1)
52-61: 🛠️ Refactor suggestion
Enhance close button accessibility
While the close button implementation is clean, consider adding accessibility props:
<Pressable onPress={() => setVisible(false)} style={styles.closeButton} + accessibilityRole="button" + accessibilityLabel="Close modal" > <FontAwesomeIcon icon={faClose} size={20} color={Colors(theme).gray100} /> </Pressable>📝 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.<Pressable onPress={() => setVisible(false)} style={styles.closeButton} accessibilityRole="button" accessibilityLabel="Close modal" > <FontAwesomeIcon icon={faClose} size={20} color={Colors(theme).gray100} /> </Pressable>contexts/collaboration-context.provider.tsx (2)
49-56:
⚠️ Potential issueAdd error handling and input validation
The
updateCollaborationmethod needs error handling and input validation:const updateCollaboration = async ( id: string, collaboration: Partial<ICollaboration>, ): Promise<void> => { + if (!id?.trim()) { + throw new Error('Invalid collaboration ID'); + } + + try { const collaborationRef = doc(FirestoreDB, "collaborations", id); await updateDoc(collaborationRef, collaboration); + } catch (error) { + console.error('Failed to update collaboration:', error); + throw new Error('Failed to update collaboration. Please try again.'); + } }📝 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.const updateCollaboration = async ( id: string, collaboration: Partial<ICollaboration>, ): Promise<void> => { if (!id?.trim()) { throw new Error('Invalid collaboration ID'); } try { const collaborationRef = doc(FirestoreDB, "collaborations", id); await updateDoc(collaborationRef, collaboration); } catch (error) { console.error('Failed to update collaboration:', error); throw new Error('Failed to update collaboration. Please try again.'); } }
42-47:
⚠️ Potential issueAdd error handling for Firestore operations
The
createCollaborationmethod should include error handling:const createCollaboration = async ( collaboration: ICollaboration, ): Promise<void> => { + try { const collaborationRef = collection(FirestoreDB, "collaborations"); await addDoc(collaborationRef, collaboration); + } catch (error) { + console.error('Failed to create collaboration:', error); + throw new Error('Failed to create collaboration. Please try again.'); + } }📝 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.const createCollaboration = async ( collaboration: ICollaboration, ): Promise<void> => { try { const collaborationRef = collection(FirestoreDB, "collaborations"); await addDoc(collaborationRef, collaboration); } catch (error) { console.error('Failed to create collaboration:', error); throw new Error('Failed to create collaboration. Please try again.'); } }components/ui/modal/DocumentUploadModal.tsx (1)
82-90: 🛠️ Refactor suggestion
Add accessibility and visual feedback to upload buttons
While the switch to Pressable components is good, they're missing important properties for accessibility and user feedback.
Add accessibility and visual feedback:
<Pressable onPress={openGallery} style={styles.modalButton} + accessibilityRole="button" + accessibilityLabel="Upload image from gallery" + android_ripple={{ color: 'rgba(0, 0, 0, 0.1)' }} + style={({ pressed }) => [ + styles.modalButton, + pressed && { opacity: 0.7 } + ]} > <FontAwesomeIcon icon={faImage} size={20} /> </Pressable>Apply similar changes to the document upload button as well.
Also applies to: 91-99
components/ui/modal/ImageUploadModal.tsx (1)
93-101: 🛠️ Refactor suggestion
Maintain consistency with DocumentUploadModal
While the error handling is good, the Pressable components need the same accessibility improvements as DocumentUploadModal.
Add accessibility and visual feedback:
<Pressable onPress={openCamera} style={styles.modalButton} + accessibilityRole="button" + accessibilityLabel="Take photo with camera" + android_ripple={{ color: 'rgba(0, 0, 0, 0.1)' }} + style={({ pressed }) => [ + styles.modalButton, + pressed && { opacity: 0.7 } + ]} > <FontAwesomeIcon icon={faCamera} size={20} /> </Pressable>Apply similar changes to the gallery upload button as well.
Also applies to: 102-110
components/ui/select/index.tsx (1)
75-79:
⚠️ Potential issueRemove duplicate
keypropThe
keyprop is unnecessarily duplicated on both thePressableand innerViewcomponents. The outerkeyis sufficient for React's reconciliation.<Pressable key={item.value} onPress={() => handleSelect(item)} > <View - key={item.value} style={[Also applies to: 80-80
components/channel/channel-list.tsx (1)
107-123: 🛠️ Refactor suggestion
Add accessibility attributes to Pressable
The add group button should have accessibility attributes for better screen reader support.
<Pressable + accessibilityLabel="Add new group" + accessibilityRole="button" onPress={() => setModalVisible(true)} style={{📝 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.<Pressable accessibilityLabel="Add new group" accessibilityRole="button" onPress={() => setModalVisible(true)} style={{ position: "absolute", right: 10, bottom: 10, backgroundColor: Colors(theme).aliceBlue, padding: 10, borderRadius: 10, }} > <FontAwesomeIcon color={Colors(theme).gray100} icon={faPlus} size={20} /> </Pressable>app/(main)/(drawer)/(tabs)/_layout.tsx (1)
107-109: 🛠️ Refactor suggestion
Add error handling for navigation
Consider adding error handling for the navigation action to handle potential routing issues.
tabPress: (e) => { e.preventDefault(); - router.push({ - pathname: "/(modal)/create-collaboration", - }); + try { + router.push({ + pathname: "/(modal)/create-collaboration", + }); + } catch (error) { + console.error('Navigation failed:', error); + // Consider showing a user-friendly error message + } },Committable suggestion skipped: line range outside the PR's diff.
app/_layout.tsx (1)
146-148: 🛠️ Refactor suggestion
Consider adding consistent presentation options
The edit-collaboration screen should maintain consistency with create-collaboration screen's presentation options.
<Stack.Screen name="(modal)/edit-collaboration" + options={{ + presentation: "formSheet", + gestureEnabled: true, + }} />📝 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.<Stack.Screen name="(modal)/edit-collaboration" options={{ presentation: "formSheet", gestureEnabled: true, }} />components/create-collaboration/screen-one.tsx (2)
185-197:
⚠️ Potential issueAdd budget range validation
The validation checks for empty fields but doesn't ensure that budgetMin <= budgetMax.
if ( !data.collaborationName || !data.aboutCollab || !data.budgetMin || !data.budgetMax || !data.numInfluencers || !data.promotionType || !data.collabType || !data.platform ) { Toaster.error("Please fill all fields"); return; } +const minBudget = parseFloat(data.budgetMin); +const maxBudget = parseFloat(data.budgetMax); +if (isNaN(minBudget) || isNaN(maxBudget)) { + Toaster.error("Please enter valid budget values"); + return; +} +if (minBudget > maxBudget) { + Toaster.error("Minimum budget cannot be greater than maximum budget"); + return; +} setScreen(2);📝 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.if ( !data.collaborationName || !data.aboutCollab || !data.budgetMin || !data.budgetMax || !data.numInfluencers || !data.promotionType || !data.collabType || !data.platform ) { Toaster.error("Please fill all fields"); return; } const minBudget = parseFloat(data.budgetMin); const maxBudget = parseFloat(data.budgetMax); if (isNaN(minBudget) || isNaN(maxBudget)) { Toaster.error("Please enter valid budget values"); return; } if (minBudget > maxBudget) { Toaster.error("Minimum budget cannot be greater than maximum budget"); return; }
91-107: 🛠️ Refactor suggestion
Consider adding numeric keyboard and input validation
The budget inputs should use numeric keyboard and validate input to ensure only valid numbers are entered.
<TextInput label="Budget Min" mode="outlined" onChangeText={(text) => setState.budgetMin(text)} style={styles.budgetInput} textColor={Colors(theme).text} value={data.budgetMin} + keyboardType="numeric" + onChangeText={(text) => { + if (/^\d*\.?\d*$/.test(text)) { + setState.budgetMin(text); + } + }} />Committable suggestion skipped: line range outside the PR's diff.
Summary by CodeRabbit
Release Notes
New Features
EditCollaborationScreenfor editing collaboration details.ProfileIconcomponent for easier navigation to user profiles.Improvements
NotificationsScreenwith a new header component.Bug Fixes
ApplicationsTabContentandInvitationsTabContentcomponents to ensure proper display across devices.Chores