Repository navigation
New profile UI changes - #44
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
added constant and bottomsheetmodal
* new profile changes
WalkthroughThe pull request includes significant changes across multiple components related to collaboration management and influencer interactions. Key updates involve the Changes
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (24)
✅ Files skipped from review due to trivial changes (2)
🔇 Additional comments (20)components/ui/carousel/render-media-item.tsx (1)
The addition of ActivityIndicator and useState hook with proper state initialization follows React Native best practices. Also applies to: 15-16, 42-42 components/ui/screen-header/index.tsx (3)
The new optional
Setting Line range hint Since this PR involves profile UI changes, please ensure that the ✅ Verification successfulThese scripts will help us understand:
The hideAction prop is not being used in profile-related screens Based on the search results, none of the profile-related screens (
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for ScreenHeader usage in profile-related files
rg -l "ScreenHeader" | rg -i "profile" | xargs rg "hideAction"
Length of output: 58 Script: #!/bin/bash
# First, let's find all files that contain ScreenHeader
rg -l "ScreenHeader"
Length of output: 564 Script: #!/bin/bash
# Let's also search for profile-related screens that might use ScreenHeader
rg -l "<ScreenHeader"
Length of output: 567 Script: #!/bin/bash
# Search for actual usage of ScreenHeader component with its props
rg -A 3 "<ScreenHeader"
Length of output: 3511 components/collaboration/collaboration-details/InvitationsTabContent.tsx (2)
The addition of the Also applies to: 46-49
Add null checks and consider simplifying the data structure The current transformation of the influencer data adds unnecessary nesting and could be prone to errors if Consider adding null checks and simplifying: influencer={{
...item,
profile: {
attachments: [
{
type: "image",
- imageUrl: item.profileImage,
+ imageUrl: item.profileImage ?? null,
},
]
}
}}Also, verify if this nested structure is really necessary. If ✅ Verification successfulBased on the shell script results, I can now provide a final response: The nested profile structure is required and matches the component's expectations The data={influencer.profile?.attachments?.map((attachment) => processRawAttachment(attachment)) || []}The transformation is necessary because:
However, you're right about adding a null check for profile: {
attachments: [
{
type: "image",
imageUrl: item.profileImage || null,
},
]
}🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check how InfluencerCard uses the profile.attachments structure
ast-grep --pattern 'profile?.attachments'
Length of output: 43 Script: #!/bin/bash
# Let's try to find the InfluencerCard component and see how it handles profile data
fd InfluencerCard --type f --exec cat {}
Length of output: 11665 Script: #!/bin/bash
# Search for any usage of profile attachments with ripgrep for broader context
rg -A 5 "profile.*attachments"
Length of output: 419 Script: #!/bin/bash
# Look for profile image usage patterns in the codebase
rg -A 3 "profileImage|imageUrl"
Length of output: 8603 components/collaboration/collaboration-details/OverviewTabContent.tsx (2)
Extract magic number to constants and consider additional breakpoints. The fixed width of 768px should be defined in a constants file for better maintainability. Also, consider adding intermediate breakpoints for more granular control over the layout. + // In constants/layout.ts
+ export const CONTENT_WIDTH = {
+ tablet: 768,
+ desktop: 1024,
+ } as const;
// In component
- width: xl ? 768 : '100%',
+ width: xl ? CONTENT_WIDTH.tablet : '100%',Let's check if similar magic numbers are used elsewhere: components/InfluencerCard.tsx (6)
The new imports are necessary for the added functionalities and are correctly implemented.
Updating the
The addition of optional props
Fetching the
Properly setting the selected influencer when triggering the modal enhances user experience.
Processing the media attachments correctly prepares the data for the styles/InfluencerCard.styles.tsx (1)
The new contexts/collaboration-context.provider.tsx (1)
The context API changes might affect other components using these methods. Let's verify the usage: ✅ Verification successfulContext changes have been properly implemented across components The verification shows that all components are correctly using the Collaboration Context:
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for components using collaboration context methods
echo "Searching for components using collaboration context..."
rg -l "useCollaborationContext|CollaborationContext.Provider" --type tsx
# Search for direct Firebase operations that should use context
echo "Checking for direct Firebase operations..."
rg -l "collection\(.*collaborations\)|doc\(.*collaborations\)" --type tsx
Length of output: 422 Script: #!/bin/bash
# Search for components using collaboration context methods without file type restriction
echo "Searching for components using collaboration context..."
rg -l "useCollaborationContext|CollaborationContext.Provider"
# Search for direct Firebase operations that should use context
echo "Checking for direct Firebase operations..."
rg -l "collection\(.*collaborations\)|doc\(.*collaborations\)"
# Search for any imports or usage of collaboration-related functions
echo "Checking for collaboration-related imports and usage..."
rg -l "getCollaborationById|createCollaboration|updateCollaboration"
Length of output: 804 Script: #!/bin/bash
# Let's check the actual usage of these methods in the components
echo "Checking usage in create-collaboration component..."
rg "getCollaborationById|createCollaboration|updateCollaboration" -C 3 "components/create-collaboration/index.tsx"
echo "\nChecking usage in notifications screen..."
rg "getCollaborationById|createCollaboration|updateCollaboration" -C 3 "app/(main)/(screens)/notifications.tsx"
echo "\nChecking context imports..."
rg "useCollaborationContext" -C 2 "components/create-collaboration/index.tsx" "app/(main)/(screens)/notifications.tsx"
Length of output: 3226 app/(main)/(drawer)/(tabs)/_layout.tsx (1)
The change from direct string path to pathname object might affect the navigation state preservation. Ensure that:
✅ Verification successfulThe previous script failed because the typescript file type wasn't recognized. Let's try searching across all files and also look for Link component usage to understand the navigation patterns better. Navigation pattern is consistent with codebase usage The codebase shows consistent usage of
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for other router.push usage patterns to ensure consistency
rg "router\.push\(" --type typescript
Length of output: 74 Script: #!/bin/bash
# Search for router.push patterns across all files
rg "router\.push\("
# Also search for Link component usage as it's commonly used for navigation in Next.js
rg "import.*Link.*from.*next/link"
Length of output: 1764 app/_layout.tsx (1)
The addition of
✅ Verification successfulProvider order is correctly implemented The BottomSheetModalProvider's placement is appropriate because:
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for bottom sheet modal usage across the codebase
rg "useBottomSheetModal|BottomSheetModal" --type typescript
# Search for potential context dependencies
rg "useContext.*Bottom" --type typescript
Length of output: 175 Script: #!/bin/bash
# Search for bottom sheet modal usage and context dependencies with proper file extensions
rg "useBottomSheetModal|BottomSheetModal" -g "*.{ts,tsx,js,jsx}"
# Search for potential context dependencies
rg "useContext.*Bottom" -g "*.{ts,tsx,js,jsx}"
# Look for imports to understand dependencies
rg "import.*BottomSheetModal" -g "*.{ts,tsx,js,jsx}"
# Search for gesture handler dependencies
rg "GestureHandlerRootView|gestureHandlerRootHOC" -g "*.{ts,tsx,js,jsx}"
Length of output: 1203 components/BottomSheetActions.tsx (1)
The navigation assumes components/FilterModal.tsx (1)
The new icon import and isVisible prop are well-structured and properly documented. Also applies to: 27-27 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: 25
🧹 Outside diff range and nitpick comments (24)
components/ui/carousel/render-media-item.tsx (2)
53-67: Consider adding accessibility attributes to the loading state.While the loading indicator implementation is good, consider enhancing accessibility for screen readers.
<View style={[ styles.loadingIndicatorContainer, { display: isLoading ? "flex" : "none", } ]} + accessibilityRole="progressbar" + accessibilityLabel="Loading image" + accessibilityLiveRegion="polite" > {isLoading && <ActivityIndicator />} </View>Also applies to: 78-79
112-113: Enhance video error handling and loading state feedback.Consider providing more detailed error handling and user feedback for video loading failures.
<Video // ... existing props onError={(error) => { - console.error("Video Error:", error) + console.error("Video Error:", error); + setIsLoading(false); + // Consider showing an error state UI }} onLoadStart={() => setIsLoading(true)} onLoad={() => setIsLoading(false)} />components/collaboration/collaboration-details/ApplicationsTabContent.tsx (3)
20-22: Add proper TypeScript types for props and breakpoints.Consider adding proper TypeScript interfaces for component props and breakpoint values.
+interface ApplicationsTabContentProps { + pageID: string; + collaboration: any; // Define proper type +} -const ApplicationsTabContent = (props: any) => { +const ApplicationsTabContent: React.FC<ApplicationsTabContentProps> = (props) => {
74-74: Consider using theme.colors for consistency.For better maintainability and consistency, consider using theme colors directly instead of the Colors utility.
-<ActivityIndicator size="large" color={Colors(theme).primary} /> +<ActivityIndicator size="large" color={theme.colors.primary} />
110-111: Consider using more flexible responsive design patterns.The current implementation uses a fixed width for xl breakpoint. Consider using relative units or a more flexible approach.
-width: xl ? 768 : '100%', +width: xl ? '80%' : '100%', +maxWidth: 768,components/ui/screen-header/index.tsx (1)
43-65: Simplify the action button implementation.The current implementation has some redundant styling and could be more efficient.
Consider these improvements:
- { - !hideAction && ( - <Appbar.Action - icon={() => ( - <View - style={{ - marginTop: 2, - }} - lightColor={Colors(theme).transparent} - darkColor={Colors(theme).transparent} - > - <FontAwesomeIcon - icon={faArrowLeft} - size={20} - color={Colors(theme).text} - /> - </View> - )} - color={Colors(theme).text} - onPress={handleAction} - /> - ) - } + {!hideAction && ( + <Appbar.Action + style={{ marginTop: 2 }} + icon={({ size, color }) => ( + <FontAwesomeIcon + icon={faArrowLeft} + size={20} + color={Colors(theme).text} + /> + )} + onPress={handleAction} + /> + )}Changes:
- Removed redundant View wrapper
- Removed unnecessary transparent color settings
- Moved marginTop to Appbar.Action's style prop
- Simplified the conditional rendering structure
components/collaboration/collaboration-details/InvitationsTabContent.tsx (2)
158-159: LGTM: Good responsive design practiceThe conditional width constraint and auto margins provide a better reading experience on larger screens. Consider extracting the magic number 768 to a constant for better maintainability.
+const MAX_CONTENT_WIDTH = 768; + <FlatList style={{ - width: xl ? 768 : '100%', + width: xl ? MAX_CONTENT_WIDTH : '100%', marginHorizontal: "auto", }} />
Line range hint
51-71: Improve error handling in handleCollaborationInviteThe current error handling only logs to console and shows a generic message. Consider:
- Adding specific error types and messages
- Cleaning up state in a consistent order
try { setIsInviting(true); const invitationRef = collection( FirestoreDB, "collaborations", props.pageID, "invitations" ); const invitationPayload = { userId: selectedInfluencer.influencerID, managerId: AuthApp.currentUser?.uid, collaborationId: selectedInfluencer.collaborationID, status: "pending", message: message, }; await addDoc(invitationRef, invitationPayload); setIsMessageModalVisible(false); Toaster.success("Invitation sent successfully"); } catch (error) { - console.error(error); - Toaster.error("Failed to send invitation"); + console.error('Failed to send invitation:', error); + Toaster.error(error instanceof Error + ? `Failed to send invitation: ${error.message}` + : "Failed to send invitation"); } finally { setMessage(""); setIsInviting(false); + setSelectedInfluencer(null); }components/collaboration/collaboration-details/OverviewTabContent.tsx (2)
23-25: Consider adding type information for the breakpoint value.While the code works correctly, adding type information would improve maintainability and provide better IDE support.
- const { - xl, - } = useBreakpoints(); + const { + xl + }: { xl: boolean } = useBreakpoints();
Line range hint
42-93: Review and update hardcoded values and duplicate content.Several improvements needed in the content sections:
- The same description is used in both "Ad Description" and "About Brand" sections
- Platform is hardcoded to "Instagram"
- Payment verification shows a hardcoded "True"
Consider:
- Using distinct content for each section
- Making platform dynamic based on collaboration data
- Using proper boolean rendering for payment verification
- <Paragraph style={styles.paragraph}>Instagram</Paragraph> + <Paragraph style={styles.paragraph}>{collaboration.platform}</Paragraph> - <Paragraph style={styles.brandName}>True</Paragraph> + <Paragraph style={styles.brandName}> + {collaboration.paymentVerified ? "Yes" : "No"} + </Paragraph>components/create-collaboration/index.tsx (1)
205-206: Provide user feedback on submission errorsIn the
catchblock, errors are logged to the console, but the user is not informed about the error. Consider displaying an error message to the user to inform them that the submission failed.Apply this diff to inform the user:
} catch (error) { console.error(error); + Toaster.error("Failed to submit collaboration. Please try again."); }components/explore-influencers/index.tsx (2)
97-106: Remove commented-out code or implement the filtersThe
filterInfluencersfunction contains several lines of commented-out code related to filters for followers, reach, and engagement ranges. Removing unused code can improve readability and maintainability. If these filters are planned for future implementation, consider adding aTODOcomment.
273-273: Handle potentialnullforselectedInfluencerThe
ProfileBottomSheetcomponent receivesselectedInfluencerwithout checking if it'snull. WhileselectedInfluenceris set before opening the modal, adding a null check can prevent potential runtime errors.Apply this diff to add a null check:
<ProfileBottomSheet - influencer={selectedInfluencer as User} + influencer={selectedInfluencer as User | undefined} theme={theme} isBrandsApp={true} />And update the
ProfileBottomSheetcomponent to handle anundefinedinfluencer.utils/text.ts (1)
1-5: Consider handling cases wherelengthis zero or negativeIf
lengthis zero or negative, the function will return the fulltext. Consider adding validation forlengthto ensure it is a positive integer, or handle these cases appropriately.Apply this diff to validate
length:export const truncateText = (text: string, length: number) => { if (!text) return ""; + if (length <= 0) return ""; return text.length > length ? text.slice(0, length) + "..." : text; };components/create-collaboration/screen-three.tsx (2)
22-35: Add accessibility attributes to improve user experience.The success screen should be more accessible to screen readers.
Apply these changes:
<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}> + <Title style={styles.title} accessibilityRole="header"> Collaboration {type === "Add" ? "Posted" : "Updated"} </Title> - <Text style={styles.description}> + <Text style={styles.description} accessibilityRole="text"> Your collaboration has been successfully {type === "Add" ? "posted" : "updated"}. </Text> </View>
14-38: Consider making this a reusable success screen component.This success screen pattern could be useful in other parts of the application.
Consider generalizing it into a reusable component:
interface SuccessScreenProps { title: string; description: string; iconSize?: number; onDismiss?: () => void; } const SuccessScreen: React.FC<SuccessScreenProps> = ({ title, description, iconSize = 100, onDismiss, }) => { // ... implementation }components/ui/bottom-sheet/BottomSheet.tsx (1)
33-38: Consider adding error handling for sheet refThe
handleClosefunction assumes the ref will always be valid. Consider adding error handling for cases where the ref might be null.const handleClose = () => { + try { if (sheetRef.current) { sheetRef.current.close(); } onClose(); + } catch (error) { + console.error('Failed to close bottom sheet:', error); + onClose(); // Ensure we still call onClose even if sheet closing fails + } };app/_layout.tsx (1)
149-152: Document formSheet presentation mode impactThe change from 'modal' to 'formSheet' presentation mode will affect the user experience. Please:
- Document the reasoning behind this change
- Update relevant UI/UX documentation
- Consider adding a comment explaining the choice of 'formSheet'
components/create-collaboration/screen-two.tsx (1)
125-128: Add validation for link display.The link rendering logic doesn't handle empty or malformed links, which could lead to rendering issues.
- <Paragraph key={index + link.url}> - {link.name}: {link.url} - </Paragraph> + <Paragraph key={index + link.url}> + {link.name ? `${link.name}: ` : ''}{link.url || 'Invalid URL'} + </Paragraph>components/create-collaboration/screen-one.tsx (1)
84-84: Uncomment multiline prop for better description input.The commented
multilineprop would improve the user experience for entering longer collaboration descriptions.- // multiline + multiline + numberOfLines={4}components/BottomSheetActions.tsx (2)
Line range hint
19-24: Replaceanytypes with proper interfaces.The component uses
anytype fordataandcardIdprops, which could lead to type-safety issues.- data?: any; // TODO: Update with the correct type - cardId?: any; + data?: { + collaboration?: { + id: string; + name: string; + }; + }; + cardId?: string | { + collaborationID: string; + applicationID: string; + influencerID: string; + };
254-265: Add loading state for navigation.The edit collaboration navigation should show a loading state while the navigation is in progress.
+ const [isNavigating, setIsNavigating] = React.useState(false); + // ... in the List.Item title="Edit Collaboration" + disabled={isNavigating} onPress={() => { + setIsNavigating(true); handleClose(); router.push({ pathname: "/edit-collaboration", params: { id: cardId, }, - }); + }).finally(() => setIsNavigating(false)); }}components/FilterModal.tsx (2)
Line range hint
92-92: Consider extracting the BottomSheet indices into constantsThe -1 and 1 values used for the BottomSheet index could be extracted into named constants for better maintainability.
+ const BOTTOM_SHEET_STATES = { + HIDDEN: -1, + VISIBLE: 1, + } as const; <BottomSheet ref={sheetRef} - index={isVisible ? 1 : -1} + index={isVisible ? BOTTOM_SHEET_STATES.VISIBLE : BOTTOM_SHEET_STATES.HIDDEN}
Line range hint
177-178: Fix incorrect state usage in Reach range displayThe Reach range display is incorrectly using
localFollowersRangeinstead oflocalReachRangefor min/max values.<Text style={styles.salaryLabel}> - Min Reach: {localFollowersRange[0].toLocaleString() || "0"} + Min Reach: {localReachRange[0].toLocaleString() || "0"} </Text>
🛑 Comments failed to post (25)
package.json (1)
68-68: 💡 Codebase verification
HTML content is not properly sanitized, potential security risk
The implementation in InfluencerCard.tsx directly renders HTML content from user profiles without any sanitization. The
truncateTextutility only handles string length and doesn't sanitize HTML content. This poses a potential XSS risk.
components/InfluencerCard.tsx: The RenderHTML component renders raw HTML frominfluencer?.profile?.content?.aboutwithout sanitization- No HTML sanitization utilities found in the codebase
Consider:
- Using the
tagsStylesandignoredTagsprops in RenderHTML to restrict allowed HTML elements- Implementing HTML sanitization before rendering content
- Using a sanitization library like DOMPurify or setting up proper content validation on the backend
🔗 Analysis chain
LGTM! But verify HTML content sanitization.
The addition of
react-native-render-htmlis appropriate for rendering HTML content in the bio display. However, ensure proper content sanitization is implemented to prevent XSS attacks.Let's verify the implementation:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check how react-native-render-html is being used in InfluencerCard.tsx # Specifically looking for sanitization options or dangerous props # Search for RenderHTML usage ast-grep --pattern 'RenderHTML { $$$ }' # Search for any sanitization or security-related props rg -A 5 'contentWidth|baseStyle|ignoredDomTags|ignoredStyles|enableExperimentalBRCollapsing'Length of output: 570
Script:
#!/bin/bash # Let's examine the full implementation of InfluencerCard.tsx to understand the context # and any potential sanitization measures # Get the full content of InfluencerCard.tsx cat components/InfluencerCard.tsx # Also check for any custom sanitization utilities rg -l "sanitize|xss|clean.*html|purify"Length of output: 9638
Script:
#!/bin/bash # Let's check the truncateText utility and any HTML processing cat utils/text.ts # Also check if there's any HTML sanitization in the project's utilities fd -e ts -e js -x cat {} \; -p "utils/"Length of output: 4910
components/collaboration/collaboration-details/InvitationsTabContent.tsx (1)
27-27: 🛠️ Refactor suggestion
Define proper TypeScript interface for component props
Using
anytype reduces type safety. Consider defining a proper interface for the component props.interface InvitationsTabContentProps { pageID: string; // add other required props } const InvitationsTabContent = (props: InvitationsTabContentProps) => {components/InfluencerCard.tsx (4)
119-131: 🛠️ Refactor suggestion
Refactor to reduce code duplication in
onPresshandlersThe
onPresshandlers in bothPressablecomponents are identical. Consider extracting the logic into a separate function to avoid code duplication and improve maintainability.Apply this refactor:
+const handleOpenProfile = () => { + if (props.openProfile) { + props.openProfile(influencer); + } +}; <Pressable onPress={handleOpenProfile} > <Avatar.Image size={50} source={imageUrl(influencer.profileImage)} /> </Pressable> <Pressable style={styles.nameContainer} onPress={handleOpenProfile} > <Text style={styles.name}>{influencer.name}</Text> <Text style={styles.handle}>{influencer.socials?.[0] || 'influencer-handle'}</Text> </Pressable>Also applies to: 132-142
207-207:
⚠️ Potential issueHandle potential
NaNvalues when converting backend dataIf
influencer.backend?.followers,reach, orratingareundefined, callingNumber(undefined)will result inNaN, which may cause unexpected behavior inconvertToKUnits. Consider providing default values to ensure reliable display.Apply this fix:
-{convertToKUnits(Number(influencer.backend?.followers))} +{convertToKUnits(Number(influencer.backend?.followers ?? 0))} -{convertToKUnits(Number(influencer.backend?.reach))} +{convertToKUnits(Number(influencer.backend?.reach ?? 0))} -{influencer.backend?.rating} +{influencer.backend?.rating ?? 'N/A'}Also applies to: 217-217, 227-227
248-264:
⚠️ Potential issueEnsure safe handling of
aboutcontent when rendering HTMLIf
influencer?.profile?.content?.aboutisundefined, passing it totruncateTextmay result in an error. Provide a default empty string to prevent potential issues.Apply this fix:
html: - truncateText(influencer?.profile?.content?.about as string, 160) || - "<p>No content available.</p>", + truncateText(influencer?.profile?.content?.about ?? '', 160) || + "<p>No content available.</p>",📝 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.<RenderHTML contentWidth={screenWidth} source={{ html: truncateText(influencer?.profile?.content?.about ?? '', 160) || "<p>No content available.</p>", }} defaultTextProps={{ style: { color: Colors(theme).text, fontSize: 16, lineHeight: 22, }, }} /> </Text> </Pressable>
272-274: 🛠️ Refactor suggestion
Replace hardcoded job statistics with dynamic data
The job statistics are currently hardcoded. Use actual data from the
influencerobject to provide accurate information.Apply this fix:
-10 Jobs completed 100% success rate +{influencer.jobsCompleted} Jobs completed ({influencer.successRate}% success rate)Ensure that
jobsCompletedandsuccessRateproperties are available in theinfluencerobject.📝 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.{/* {influencer.jobsCompleted} Jobs completed ({influencer.successRate}{" "} success rate) */} {influencer.jobsCompleted} Jobs completed ({influencer.successRate}% success rate)components/create-collaboration/index.tsx (4)
147-149:
⚠️ Potential issueHandle the case when the user is not logged in
If the user is not logged in, the function logs an error but continues execution, which may lead to unexpected behavior. Consider returning early to prevent further execution.
Apply this diff to handle the case:
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-164: 🛠️ Refactor suggestion
Validate budget inputs and ensure logical correctness
The current validation checks if
budgetMinandbudgetMaxare non-empty strings, but does not validate whether they are valid numbers or ifbudgetMinis less than or equal tobudgetMax. This could result in inconsistent or incorrect data. Consider adding validation to ensure thatbudgetMinandbudgetMaxare valid numbers and maintain logical consistency.Apply this diff to enhance validation:
if ( !collaborationName || !aboutCollab || !budgetMin || !budgetMax || !promotionType.length || !collabType.length || !numInfluencers || !platform.length || !location ) { Toaster.error("Please fill all fields"); return; } + if (isNaN(Number(budgetMin)) || isNaN(Number(budgetMax))) { + Toaster.error("Budget values must be valid numbers"); + return; + } + if (Number(budgetMin) > Number(budgetMax)) { + Toaster.error("Minimum budget cannot be greater than maximum budget"); + 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 || !promotionType.length || !collabType.length || !numInfluencers || !platform.length || !location ) { Toaster.error("Please fill all fields"); return; } if (isNaN(Number(budgetMin)) || isNaN(Number(budgetMax))) { Toaster.error("Budget values must be valid numbers"); return; } if (Number(budgetMin) > Number(budgetMax)) { Toaster.error("Minimum budget cannot be greater than maximum budget"); return; }
151-161:
⚠️ Potential issueValidate that arrays have elements before submission
The current validation checks whether
promotionType,collabType, andplatformare truthy, but does not check if they have elements. An empty array is truthy in JavaScript, which may lead to runtime errors when accessing index 0. Consider validating that these arrays have at least one element before proceeding.Apply this diff to enhance validation:
if ( !collaborationName || !aboutCollab || !budgetMin || !budgetMax || - !promotionType || - !collabType || - !numInfluencers || - !platform || !location + !promotionType.length || + !collabType.length || + !numInfluencers || + !platform.length || ) { Toaster.error("Please fill all fields"); 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 || !promotionType.length || !collabType.length || !numInfluencers || !platform.length || !location ) {
187-190:
⚠️ Potential issueEnsure arrays have elements before accessing index 0
The code assumes that
promotionType,collabType, andplatformarrays have at least one element by accessing index 0 directly. This may cause runtime errors if any of these arrays are empty. Consider adding checks or default values before accessing these arrays.Apply this diff to prevent potential errors:
await handleCollaboration({ //... - promotionType: promotionType[0].value as PromotionType, + promotionType: promotionType[0]?.value as PromotionType, - collaborationType: collabType[0].value as CollaborationType, + collaborationType: collabType[0]?.value as CollaborationType, //... - platform: platform[0].value as SocialPlatform, + platform: platform[0]?.value as SocialPlatform, //... });Additionally, ensure that these arrays have elements before accessing them or provide default values if necessary.
Committable suggestion skipped: line range outside the PR's diff.
components/explore-influencers/index.tsx (1)
107-109:
⚠️ Potential issueEnsure
influencer.nameis defined before callingtoLowerCase()If
influencer.nameisundefinedornull, callingtoLowerCase()will cause a runtime error. Consider adding a null check or a default value to prevent this error.Apply this diff to handle undefined names:
const isSearchQueryMatch = influencer.name - .toLowerCase() + ?.toLowerCase() .includes(searchQuery.toLowerCase());Or provide a default empty string:
const isSearchQueryMatch = (influencer.name || "") .toLowerCase() .includes(searchQuery.toLowerCase());📝 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 isSearchQueryMatch = influencer.name ?.toLowerCase() .includes(searchQuery.toLowerCase());const isSearchQueryMatch = (influencer.name || "") .toLowerCase() .includes(searchQuery.toLowerCase());utils/conversion.ts (1)
2-4: 🛠️ Refactor suggestion
Handle non-finite numbers like
InfinityThe function checks if
numisNaN, but does not handle cases wherenumisInfinityor-Infinity. Consider usingNumber.isFinite(num)to ensurenumis a finite number before proceeding.Apply this diff to handle non-finite numbers:
export const convertToKUnits = (num: number) => { - if (Number.isNaN(num)) { + if (!Number.isFinite(num)) { return 0; }📝 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 (!Number.isFinite(num)) { return 0; }constants/Influencer.ts (2)
4-9:
⚠️ Potential issueUse obviously fake data for mock objects.
The current mock data contains realistic-looking personal information which could accidentally be committed or deployed.
Use clearly fake data:
- name: "John Doe", - profileImage: "https://www.pngkey.com/png/full/114-1149878_setting-user-avatar-in-specific-size-without-breaking.png", - email: "johndoe@gmail.com", - phoneNumber: "1234567890", - location: "New York", + name: "MOCK_USER_NAME", + profileImage: "https://example.com/mock-avatar.png", + email: "mock.user@example.com", + phoneNumber: "000-000-0000", + location: "MOCK_LOCATION",📝 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.name: "MOCK_USER_NAME", profileImage: "https://example.com/mock-avatar.png", email: "mock.user@example.com", phoneNumber: "000-000-0000", location: "MOCK_LOCATION",
52-55:
⚠️ Potential issueRemove @ts-ignore and properly type the arrays.
Using @ts-ignore masks potential type issues that could cause runtime errors.
Fix the type issues:
- //@ts-ignore - notifications: [], - //@ts-ignore - socials: [], + notifications: Array<never>, + socials: Array<never>,Consider adding proper types if these arrays are expected to contain data in the future.
Committable suggestion skipped: line range outside the PR's diff.
contexts/collaboration-context.provider.tsx (3)
17-21: 🛠️ Refactor suggestion
Add loading and error states to the context.
The context should provide loading and error states for better UX.
Add state management to the interface:
interface CollaborationContextProps { + loading: boolean; + error: Error | null; getCollaborationById: (id: string) => Promise<Collaboration>; createCollaboration: (collaboration: ICollaboration) => Promise<void>; updateCollaboration: (id: string, collaboration: Partial<ICollaboration>) => Promise<void>; + clearError: () => void; }📝 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 CollaborationContextProps { loading: boolean; error: Error | null; getCollaborationById: (id: string) => Promise<Collaboration>; createCollaboration: (collaboration: ICollaboration) => Promise<void>; updateCollaboration: (id: string, collaboration: Partial<ICollaboration>) => Promise<void>; clearError: () => void; }
42-47:
⚠️ Potential issueAdd error handling and validation for collaboration creation.
The createCollaboration function lacks error handling and validation.
Implement proper error handling and validation:
const createCollaboration = async ( collaboration: ICollaboration, ): Promise<void> => { + try { + // Validate collaboration data + if (!collaboration.title || !collaboration.description) { + throw new Error('Missing required fields'); + } + const collaborationRef = collection(FirestoreDB, "collaborations"); - await addDoc(collaborationRef, collaboration); + await addDoc(collaborationRef, { + ...collaboration, + createdAt: new Date().toISOString(), + }); + } catch (error) { + console.error('Failed to create collaboration:', error); + throw error; + } }📝 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 { // Validate collaboration data if (!collaboration.title || !collaboration.description) { throw new Error('Missing required fields'); } const collaborationRef = collection(FirestoreDB, "collaborations"); await addDoc(collaborationRef, { ...collaboration, createdAt: new Date().toISOString(), }); } catch (error) { console.error('Failed to create collaboration:', error); throw error; } }
49-56:
⚠️ Potential issueAdd error handling and optimistic updates for collaboration updates.
The updateCollaboration function should handle errors and implement optimistic updates for better UX.
Implement error handling and optimistic updates:
const updateCollaboration = async ( id: string, collaboration: Partial<ICollaboration>, ): Promise<void> => { + try { + // Validate id + if (!id) { + throw new Error('Missing collaboration ID'); + } + const collaborationRef = doc(FirestoreDB, "collaborations", id); + + // Verify document exists + const docSnap = await getDoc(collaborationRef); + if (!docSnap.exists()) { + throw new Error('Collaboration not found'); + } - await updateDoc(collaborationRef, collaboration); + await updateDoc(collaborationRef, { + ...collaboration, + updatedAt: new Date().toISOString(), + }); + } catch (error) { + console.error('Failed to update collaboration:', error); + throw error; + } }Committable suggestion skipped: line range outside the PR's diff.
components/ui/bottom-sheet/BottomSheet.tsx (2)
28-31:
⚠️ Potential issueAdd dependency array for snapPoints memoization
The
useMemohook is missing dependencies in its dependency array. This could lead to stale values ifsnapPointsRangechanges.const snapPoints = React.useMemo( () => [snapPointsRange[0], snapPointsRange[1]], - [] + [snapPointsRange] );📝 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 snapPoints = React.useMemo( () => [snapPointsRange[0], snapPointsRange[1]], [snapPointsRange] );
40-65: 🛠️ Refactor suggestion
Add accessibility support for modal interactions
The bottom sheet modal lacks proper accessibility attributes. Consider adding:
- ARIA labels for the modal
- Focus management
- Screen reader support
<Modal visible={isVisible} transparent animationType="fade" onRequestClose={handleClose} + accessible={true} + accessibilityLabel="Bottom sheet modal" + accessibilityRole="dialog" >Committable suggestion skipped: line range outside the PR's diff.
app/_layout.tsx (1)
153-153: 🛠️ Refactor suggestion
Add consistent modal configuration
The new edit-collaboration route lacks the same modal configuration as create-collaboration. Consider applying consistent presentation options.
- <Stack.Screen name="(modal)/edit-collaboration" /> + <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-two.tsx (2)
15-26: 🛠️ Refactor suggestion
Consider using a more specific type for the links array.
The
linksproperty in the data interface is typed asany[]. This could lead to runtime errors if the link objects don't match the expected structure.- links: any[]; + links: Array<{ + name: string; + url: 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.data: { location: string; links: Array<{ name: string; url: string; }>; mapRegion: { latitude: number; longitude: number; latitudeDelta: number; longitudeDelta: number; }; newLinkName: string; newLinkUrl: string; };
142-155:
⚠️ Potential issueAdd URL validation for link inputs.
The link URL input field should validate the URL format before allowing submission.
<TextInput label="Link URL" mode="outlined" - onChangeText={setState.newLinkUrl} + onChangeText={(text) => { + setState.newLinkUrl(text); + if (text && !text.match(/^(http|https):\/\/[^ "]+$/)) { + Toaster.error('Please enter a valid URL'); + } + }} style={styles.input} value={data.newLinkUrl} + keyboardType="url" />📝 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.<TextInput label="Link Name" mode="outlined" onChangeText={setState.newLinkName} style={styles.input} value={data.newLinkName} /> <TextInput label="Link URL" mode="outlined" onChangeText={(text) => { setState.newLinkUrl(text); if (text && !text.match(/^(http|https):\/\/[^ "]+$/)) { Toaster.error('Please enter a valid URL'); } }} style={styles.input} value={data.newLinkUrl} keyboardType="url" />components/create-collaboration/screen-one.tsx (2)
185-197: 🛠️ Refactor suggestion
Enhance form validation.
The current validation only checks for empty fields. Consider adding more specific validation rules for each field type.
if ( - !data.collaborationName || - !data.aboutCollab || - !data.budgetMin || - !data.budgetMax || - !data.numInfluencers || - !data.promotionType || - !data.collabType || - !data.platform + !data.collaborationName.trim() || + !data.aboutCollab.trim() || + !data.budgetMin || Number(data.budgetMin) <= 0 || + !data.budgetMax || Number(data.budgetMax) <= Number(data.budgetMin) || + !data.numInfluencers || data.numInfluencers < 1 || + !data.promotionType.length || + !data.collabType.length || + !data.platform.length ) { - Toaster.error("Please fill all fields"); + Toaster.error("Please fill all fields correctly");📝 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.trim() || !data.aboutCollab.trim() || !data.budgetMin || Number(data.budgetMin) <= 0 || !data.budgetMax || Number(data.budgetMax) <= Number(data.budgetMin) || !data.numInfluencers || data.numInfluencers < 1 || !data.promotionType.length || !data.collabType.length || !data.platform.length ) { Toaster.error("Please fill all fields correctly"); return; }
91-107:
⚠️ Potential issueAdd budget range validation.
The budget inputs should validate that the maximum budget is greater than the minimum budget.
<TextInput label="Budget Max" mode="outlined" - onChangeText={(text) => setState.budgetMax(text)} + onChangeText={(text) => { + setState.budgetMax(text); + if (Number(text) <= Number(data.budgetMin)) { + Toaster.error('Maximum budget must be greater than minimum budget'); + } + }} style={styles.budgetInput} textColor={Colors(theme).text} value={data.budgetMax} + keyboardType="numeric" />Committable suggestion skipped: line range outside the PR's diff.
components/FilterModal.tsx (1)
134-140: 🛠️ Refactor suggestion
Optimize icon rendering and improve accessibility
The icon rendering logic could be optimized for performance and accessibility:
- The icon prop function is recreated on every render
- Missing accessibility label for the icon
+ const renderIcon = useCallback((category: string) => + localInfluencerType === category ? ( + <FontAwesomeIcon + color={Colors(theme).text} + icon={faCheckDouble} + size={14} + accessibilityLabel="Selected category" + /> + ) : null + , [localInfluencerType, theme]); <Chip - icon={() => localInfluencerType === category ? ( - <FontAwesomeIcon - color={Colors(theme).text} - icon={faCheckDouble} - size={14} - /> - ) : null} + icon={() => renderIcon(category)}Committable suggestion skipped: line range outside the PR's diff.
Summary by CodeRabbit
Release Notes
New Features
CreateCollaboration,EditCollaborationScreen, andScreenOne,ScreenTwo,ScreenThreecomponents for collaboration management.RenderMediaItemcomponent.BottomSheetContainercomponent for modal bottom sheets.Improvements
InfluencerCardandCollaborationFiltercomponents for better interactivity and visibility management.ApplicationsTabContentandInvitationsTabContentcomponents.Bug Fixes
Chores
react-native-render-html.