Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add context menu to messages #1292

Closed
wants to merge 7 commits into from

Conversation

thierryskoda
Copy link
Collaborator

@thierryskoda thierryskoda commented Dec 4, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a new Loader component for loading indicators, replacing the previous ActivityIndicator.
    • Added AttachmentContainer, AttachmentLoading, and RemoteAttachmentImage components for enhanced attachment handling in chats.
    • Implemented DmConsentPopup and GroupConsentPopup for managing user consent in conversations.
    • Added new hooks for managing group consent and conversation queries.
    • Introduced a MessageContextMenu component for managing context menus in chat messages.
    • Added MessageContextMenuAboveMessageReactions, MessageContextMenuBackdrop, and other related components for improved user interaction with message reactions.
  • Bug Fixes

    • Improved error handling in various components and hooks, ensuring better user feedback during operations.
  • Refactor

    • Streamlined the ChatGroupUpdatedMessage and MessageContextMenu components for improved functionality and readability.
    • Updated parameter types across multiple hooks to enforce stricter type requirements.
    • Refactored the MessageReactions component to simplify its interface and improve state management.
  • Chores

    • Cleaned up import statements and removed unused components to enhance code maintainability.

Copy link
Contributor

coderabbitai bot commented Dec 4, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request introduces several significant changes across multiple components in the chat application. The ActivityIndicator is replaced with a new Loader component, with appropriate updates to import statements and deprecation comments. Several components related to message handling and group consent management are added, modified, or removed, enhancing the functionality and structure of the chat interface. Notably, many components now enforce stricter prop requirements, particularly for ConversationTopic, and new hooks are introduced to manage consent states effectively.

Changes

File Change Summary
components/ActivityIndicator/ActivityIndicator.tsx Replaced ActivityIndicator with Loader, updated export statement, and added deprecation comment.
components/Chat/Attachment/AttachmentMessagePreview.tsx Deleted file containing components for handling remote attachments.
components/Chat/Attachment/attachment-container.tsx Added new AttachmentContainer component for styling attachment previews.
components/Chat/Attachment/attachment-loading.tsx Introduced AttachmentLoading component for displaying loading indicators.
components/Chat/Attachment/remote-attachment-image.tsx Added RemoteAttachmentImage component for displaying remote image attachments.
components/Chat/ChatGroupUpdatedMessage.tsx Updated ChatGroupUpdatedMessage to use message prop instead of content.
components/Chat/ConsentPopup/ConsentPopup.tsx Deleted ConsentPopup component for consent management.
components/Chat/ConsentPopup/GroupConsentPopup.tsx Deleted GroupConsentPopup component for group consent management.
components/Chat/ConsentPopup/consent-popup.design-system.tsx Added new components for consent popup interface.
components/Chat/ConsentPopup/dm-consent-popup.tsx Introduced DmConsentPopup for managing user consent for DMs.
components/Chat/Message/MessageActions.tsx Removed context menu items, affecting message interaction capabilities.
components/Chat/Message/MessageContextMenu.tsx Restructured props and simplified visibility handling for context menu.
components/Chat/Message/MessageReactionsList.tsx Refactored structure and prop management for message reactions.
components/Chat/Message/MessageTail.tsx Deleted MessageTail component for rendering message tails.
components/Chat/Message/MessageTimestamp.tsx Deleted timestamp rendering component.
components/Chat/Message/V3Message.tsx Significant refactor for message handling and rendering logic.
components/Chat/Message/components/message-container.tsx Added MessageContainer for structured message display.
components/Chat/Message/components/message-content-container.tsx Added MessageContentContainer for managing message content layout.
components/Chat/Message/components/message-layout.tsx Introduced MessageLayout for rendering chat messages.
components/Chat/Message/components/message-repliable.tsx Renamed RepliableMessageWrapper to MessageRepliable.
components/Chat/Message/components/message-space-between-messages.tsx Added MessageSpaceBetweenMessages for spacing between messages.
components/Chat/Message/message-content-types/message-remote-attachment.tsx Introduced MessageRemoteAttachment for rendering remote attachments.
components/Chat/Message/message-content-types/message-reply.tsx Added MessageReply for rendering reply messages.
components/Chat/Message/message-content-types/message-simple-text.tsx Introduced MessageSimpleText for displaying simple text messages.
components/Chat/Message/message-content-types/message-static-attachment.tsx Added MessageStaticAttachment for handling static attachments.
components/Chat/Message/message-date-change.tsx Introduced MessageDateChange for displaying message timestamps.
components/Chat/Message/message-gestures.tsx Added MessageGestures for enhanced user interactions.
components/Chat/Message/message-timestamp.tsx Introduced MessageTimestamp for displaying message timestamps.
components/Chat/Message/message-utils.tsx Added utility functions for message handling.
components/Chat/Message/stores/message-store.tsx Updated message context store with new properties.
components/Conversation/V3Conversation.tsx Refactored conversation handling and message rendering.
components/GroupAvatar.tsx Made topic prop required in GroupAvatar.
containers/GroupScreenMembersTable.tsx Updated to accept group prop for enhanced member management.
custom-eslint-plugin/padding-before-react-hooks.js Enhanced ESLint rule for blank lines before hooks.
design-system/BlurView.tsx Added FadeIn animation import.
design-system/loader.tsx Introduced Loader component for loading indicators.
features/conversation-list/hooks/useMessageText.ts Updated import paths for utility functions.
features/conversation-list/useV3ConversationItems.ts Refactored conversation filtering logic.
features/conversation/composer/add-attachment-button.tsx Updated imports and enhanced error handling.
features/conversation/composer/composer.tsx Replaced ChatInputDumb with Composer function.
features/conversation/composer/send-attachment-preview.tsx Updated to use Loader instead of ActivityIndicator.
features/conversation/conversation-context.tsx Enhanced ISendMessageParams type and context management.
features/conversation/conversation-persisted-stores.ts Updated replyingToMessageId type for improved specificity.
features/conversation/conversation-service.ts Added new functions for managing message context menus.
features/conversation/conversation-store.ts Introduced messageContextMenuData to the conversation store.
features/conversation/dm-conversation.screen.tsx Introduced new DM conversation management component.
features/conversations/components/V3ConversationFromPeer.tsx Updated import paths for conversation query hooks.
features/conversations/utils/messageIsFromCurrentUser.ts Updated import paths for utility functions.
features/search/components/NavigationChatButton.tsx Removed timeout for immediate navigation.
hooks/useGroupConsent.ts Simplified useGroupConsent hook and improved state management.
hooks/useGroupCreator.ts Updated parameter types for useGroupCreator.
hooks/useGroupMembers.ts Made topic parameter required in useGroupMembers.
ios/Converse.xcodeproj/project.pbxproj Cleaned up unused resource references.
navigation/useNavigation.tsx Introduced useRouteParams for easier route parameter access.
queries/MutationKeys.ts Removed allowGroupMutationKey function.
queries/QueryKeys.ts Added new DM_CONSENT entry to the QueryKeys enum.
queries/queryClient.ts Added retry: false to QueryClient configuration.
queries/useAddToGroupMutation.ts Made topic parameter required in useAddToGroupMutation.
queries/useAllowGroupMutation.ts Deleted useAllowGroupMutation hook.
queries/useBlockGroupMutation.ts Updated argument structure for consentToGroupsOnProtocolByAccount.
queries/useConversationQuery.ts Introduced getConversation function for fetching conversations.
queries/useConversationWithPeerQuery.ts Added useConversationWithPeerQuery hook for fetching conversations by peer.
queries/useDmConstentStateQuery.ts Introduced useDmConsentQuery for managing DM consent states.
queries/useDmPeerInbox.ts Renamed dmPeerInboxQueryKey and useDmPeerInbox for clarity.
queries/useGroupConsentQuery.ts Updated types and parameters for group consent management.
queries/useGroupDescriptionMutation.ts Made topic parameter required in useGroupDescriptionMutation.
queries/useGroupMembersQuery.ts Made topic parameter required in both query functions.
queries/useGroupNameQuery.ts Updated to use useConversationQuery for fetching group names.
queries/useGroupPermissionPolicyQuery.ts Made topic parameter required in useGroupPermissionPolicyQuery.
queries/useGroupPinnedFrameQuery.ts Made topic parameter required in useGroupPinnedFrameQuery.
queries/useGroupQuery.ts Made topic parameter required in useGroupQuery.
queries/usePromoteToAdminMutation.ts Made topic parameter required in usePromoteToAdminMutation.
queries/usePromoteToSuperAdminMutation.ts Made topic parameter required in usePromoteToSuperAdminMutation.
queries/useRemoveFromGroupMutation.ts Made topic parameter required in useRemoveFromGroupMutation.
queries/useRevokeAdminMutation.ts Made topic parameter required in useRevokeAdminMutation.
queries/useRevokeSuperAdminMutation.ts Made topic parameter required in useRevokeSuperAdminMutation.
queries/useV3ConversationListQuery.ts Exported V3ConversationListType for external use.
screens/ConversationReadOnly.tsx Updated prop for MessagesList component to messageIds.
screens/GroupInvite.tsx Added non-null assertion for newGroup?.topic.
screens/Navigation/Navigation.tsx Added new screens for onboarding and account management.
screens/NewConversation/NewConversation.tsx Updated handling of addingToGroupTopic with non-null assertion.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant Loader
    participant MessageService
    participant GroupService

    User->>App: Initiate loading
    App->>Loader: Show loading indicator
    Loader-->>App: Loading in progress
    App->>MessageService: Fetch messages
    MessageService-->>App: Messages fetched
    App->>Loader: Hide loading indicator
    App->>User: Display messages

    User->>GroupService: Request group info
    GroupService-->>User: Group info received
Loading

Possibly related PRs

  • fix: Render Frame on initial send #1067: The main PR modifies the ActivityIndicator component to use the Loader component instead, which is relevant as it indicates a shift in how loading indicators are handled in the chat application, potentially affecting the rendering of frames in chat messages.
  • fix: Fixed Buttons for Certain cases #1127: This PR updates button components to align with a design system, which may relate to the overall UI consistency, including how loading states are presented in buttons, indirectly connecting to the changes in loading indicators in the main PR.
  • fix: Group Admin Table  #1250: The updates to the group permissions and admin functionalities may relate to how the Loader component is used in contexts where group actions are performed, ensuring that loading states are appropriately managed during these operations.
  • feat: V3 Search #1261: The introduction of search functionalities for DMs and groups may involve loading states when fetching results, which could be impacted by the changes made in the main PR regarding loading indicators.
  • diff #1277: While primarily focused on build configurations, any changes to the project structure could indirectly affect how components, including loading indicators, are integrated and rendered within the application.

Suggested labels

3.0.0

🐰 In the code, we hop and play,
New loaders bring a brighter day!
With components fresh and changes grand,
Our chat app's now the best in the land!
So let’s celebrate with joy and cheer,
For all the updates that we hold dear!
🐇✨


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@thierryskoda thierryskoda changed the base branch from release/3.0.0 to ts/message-refactoring-attachments December 4, 2024 02:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (38)
components/Chat/Message/message-content-types/message-simple-text.tsx (3)

46-136: ⚠️ Potential issue

Remove commented-out context menu implementation.

The PR title indicates adding a context menu feature, but the implementation is commented out with a note about missing library functionality. This raises several concerns:

  1. Large blocks of commented code shouldn't be merged into production.
  2. The code contains debugging artifacts (debugBorder).
  3. Multiple attempted approaches suggest the solution isn't finalized.

Recommendations:

  1. Remove all commented-out code
  2. Create a separate feature branch for the context menu implementation
  3. Document the attempted approaches and challenges in the project wiki or issues
  4. Consider splitting this PR into two:
    • One for the basic MessageSimpleText component
    • Another for the context menu feature when it's ready

Would you like me to help create a GitHub issue to track the context menu implementation separately?


37-45: ⚠️ Potential issue

Remove unused library imports.

The commented-out imports for context menu libraries should be removed until the implementation is ready. Keeping unused imports makes the code harder to maintain and can lead to confusion.

-// import { MessageContextMenu } from "@/components/Chat/Message/MessageContextMenu";
-// import ContextMenu from "react-native-context-menu-view";
-// import * as ContextMenu from "zeego/context-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.

/**
 * Tried different approaches to implement native context menu, but it's not
 * working as expected. Still missing some pieces from libraries to achieve what we want
 */


12-35: 🛠️ Refactor suggestion

Consider adding error handling for message content extraction.

While the implementation is clean and well-structured, the message.content() call on line 17 lacks error handling. This could potentially throw an error if the message content is corrupted or invalid.

Consider adding a try-catch block:

-  const textContent = message.content();
+  let textContent: string;
+  try {
+    textContent = message.content();
+  } catch (error) {
+    console.error('Failed to decode message content:', error);
+    textContent = 'Message cannot be displayed';
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export const MessageSimpleText = memo(function MessageSimpleText(props: {
  message: DecodedMessage<[TextCodec]>;
}) {
  const { message } = props;

  let textContent: string;
  try {
    textContent = message.content();
  } catch (error) {
    console.error('Failed to decode message content:', error);
    textContent = 'Message cannot be displayed';
  }

  const { hasNextMessageInSeries, fromMe } = useMessageContextStoreContext(
    useSelect(["hasNextMessageInSeries", "fromMe"])
  );

  return (
    <MessageLayout>
      <BubbleContainer fromMe={fromMe}>
        <BubbleContentContainer
          fromMe={fromMe}
          hasNextMessageInSeries={hasNextMessageInSeries}
        >
          <MessageText inverted={fromMe}>{textContent}</MessageText>
        </BubbleContentContainer>
      </BubbleContainer>
    </MessageLayout>
  );
});
queries/useRevokeSuperAdminMutation.ts (1)

18-18: 🛠️ Refactor suggestion

Remove redundant null checks for topic

Since topic is now a required parameter of type ConversationTopic, the null checks throughout the code (e.g., in mutationFn and onError) are unnecessary and can be safely removed.

screens/Navigation/Navigation.tsx (1)

153-156: 🛠️ Refactor suggestion

Add screen options for consistency with other screens.

The DmConversation screen is missing screen options that are present in other screens. Consider adding header configuration for consistent UI/UX.

Here's a suggested improvement:

  <NativeStack.Screen
    name="DmConversation"
    component={DmConversationScreen}
+   options={{
+     headerLargeTitle: true,
+     headerShadowVisible: false,
+     headerBackTitle: "Back",
+     headerBackTitleVisible: false,
+   }}
  />

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

features/conversation/dm-conversation.screen.tsx (3)

48-48: 🛠️ Refactor suggestion

Avoid Suppressing TypeScript Errors with @ts-ignore

Using // @ts-ignore suppresses TypeScript errors, which can conceal underlying issues and reduce type safety. It's better to resolve the type error to ensure robust and maintainable code.

Consider properly typing props.route.params by adjusting the type definitions or casting to the appropriate type to eliminate the need for @ts-ignore.


77-77: 🛠️ Refactor suggestion

Simplify Boolean Expression by Removing Redundant Double Negation

The expression !!conversation uses a double negation, which is unnecessary since JavaScript coerces expressions in conditional statements to boolean values. Removing the double negation improves readability.

Apply this diff to simplify the expression:

-      {!!conversation ? (
+      {conversation ? (
📝 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.

      {conversation ? (
🧰 Tools
🪛 Biome (1.9.4)

[error] 77-77: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


228-236: ⚠️ Potential issue

Correct Typographical Error in Parameter Name peerAddresss

The parameter peerAddresss in the useNewConversationHeader function has an extra 's'. To maintain consistency and prevent potential bugs, rename it to peerAddress.

Apply this diff to fix the typo:

-function useNewConversationHeader(peerAddresss: string) {
+function useNewConversationHeader(peerAddress: string) {

Update all occurrences within the function:

-    navigation.setOptions({
-      headerTitle: () => <NewConversationTitle peerAddress={peerAddresss} />,
-    });
+    navigation.setOptions({
+      headerTitle: () => <NewConversationTitle peerAddress={peerAddress} />,
+    });

And adjust the dependency array in the useEffect hook:

-  }, [peerAddresss, navigation]);
+  }, [peerAddress, navigation]);
📝 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.

function useNewConversationHeader(peerAddress: string) {
  const navigation = useRouter();

  useEffect(() => {
    navigation.setOptions({
      headerTitle: () => <NewConversationTitle peerAddress={peerAddress} />,
    });
  }, [peerAddress, navigation]);
}
components/Chat/Message/message-content-types/message-static-attachment.tsx (2)

66-67: 🛠️ Refactor suggestion

Handle potential errors when writing the attachment file

Currently, the code assumes that RNFS.writeFile will always succeed. It's good practice to handle potential errors that may occur during file writing to prevent unexpected crashes or silent failures.

Consider wrapping the file writing operation in a try-catch block to handle any exceptions:

try {
  await RNFS.writeFile(attachmentPath, staticAttachment.data, "base64");
} catch (error) {
  throw new Error(`Failed to write attachment file: ${error.message}`);
}
📝 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.

      try {
        await RNFS.writeFile(attachmentPath, staticAttachment.data, "base64");
      } catch (error) {
        throw new Error(`Failed to write attachment file: ${error.message}`);
      }

92-94: ⚠️ Potential issue

Avoid potential division by zero when calculating aspectRatio

When calculating aspectRatio, there is a possibility of a division by zero if attachment.imageSize.height is zero, which would cause a runtime error.

Add a check to ensure attachment.imageSize.height is not zero before performing the division:

const aspectRatio =
  attachment.imageSize && attachment.imageSize.height !== 0
    ? attachment.imageSize.width / attachment.imageSize.height
    : undefined;
📝 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 aspectRatio =
    attachment.imageSize && attachment.imageSize.height !== 0
      ? attachment.imageSize.width / attachment.imageSize.height
      : undefined;
components/Chat/Message/message-gestures.tsx (1)

84-85: ⚠️ Potential issue

Avoid calling runOnJS inside runOnJS

The runOnJS function is used inside an onStart callback that already uses runOnJS. This can lead to unexpected behavior and performance issues.

Modify the code to use runOnJS once, and ensure callbacks are correctly handled:

.onStart((e) => {
  Haptics.softImpactAsyncAnimated();
  scaleAV.value = withTiming(MESSAGE_GESTURE_LONG_PRESS_SCALE, {
    duration: MESSAGE_GESTURE_LONG_PRESS_MIN_DURATION * 2,
    easing: Easing.bezier(0.31, 0.04, 0.03, 1.04),
  });
  const measured = measure(containerRef);
  if (!measured) return;
  if (onLongPress) {
-   runOnJS(onLongPress)({ ...e, ...measured });
+   onLongPress({ ...e, ...measured });
  }
})

Ensure that onLongPress is wrapped with runOnJS only once in the gesture configuration.

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

components/Chat/ConsentPopup/dm-consent-popup.tsx (1)

102-105: 🛠️ Refactor suggestion

Avoid swallowing errors in handleAccept

The captureErrorWithToast function captures the error but may not provide detailed feedback to the user.

Consider providing a more descriptive error message and ensure that all errors are properly logged:

} catch (error) {
  captureErrorWithToast(ensureError(error), {
-   message: `Error consenting`,
+   message: translate("error_consenting", { error: error.message }),
  });
}

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

components/Chat/Message/V3Message.tsx (1)

77-79: 🛠️ Refactor suggestion

Handle null or undefined message gracefully

Logging "no message found" may not be sufficient. It's essential to handle the absence of a message appropriately.

Consider displaying a placeholder or fallback UI component instead of returning null.

if (!message) {
- console.log("no message found", messageId);
+ return <Text>Message not found</Text>;
}

Ensure that the Text component is imported from the appropriate library.

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

components/Chat/Attachment/remote-attachment-image.tsx (1)

77-81: ⚠️ Potential issue

Implement the 'openInWebview' functionality for unsupported media types

The onPress handler in the PressableScale component is currently empty, with a placeholder comment // openInWebview. This means that users are unable to view unsupported media types as intended.

Would you like assistance in implementing the openInWebview functionality, or should I open a GitHub issue to track this task?

hooks/useGroupConsent.ts (1)

150-154: ⚠️ Potential issue

Await the call to consentToInboxIdsOnProtocolByAccount to ensure it completes

Currently, the call to consentToInboxIdsOnProtocolByAccount is not awaited, which may result in the function returning before the consent operation completes. This could lead to unexpected behavior.

Apply this diff to fix the issue:

if (inboxIdsToDeny.length > 0) {
-  consentToInboxIdsOnProtocolByAccount({
+  await consentToInboxIdsOnProtocolByAccount({
    account,
    inboxIds: inboxIdsToDeny,
    consent: "deny",
  });
}
📝 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 (includeCreator && groupCreator) {
        inboxIdsToDeny.push(groupCreator);
      }

      if (inboxIdsToDeny.length > 0) {
        await consentToInboxIdsOnProtocolByAccount({
          account,
          inboxIds: inboxIdsToDeny,
          consent: "deny",
        });
      }
components/Chat/Message/components/message-layout.tsx (1)

145-145: 🛠️ Refactor suggestion

Remove redundant double-negation in condition

The double-negation !! is unnecessary since the condition in the if statement will coerce messageStringContent to a boolean automatically.

Apply this diff to remove the redundant double-negation:

-                if (!!messageStringContent) {
+                if (messageStringContent) {
📝 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 (messageStringContent) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 145-145: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

components/Chat/ChatGroupUpdatedMessage.tsx (1)

33-35: ⚠️ Potential issue

Handle string content returned by message.content()

The check for typeof content === "string" leads to a return null with a TODO comment. This indicates that handling for string content is not implemented, which might cause issues if message.content() returns a string.

Would you like assistance in implementing the handling for string content, or should I open a GitHub issue to track this?

components/Chat/Message/message-content-types/message-reply.tsx (1)

174-183: ⚠️ Potential issue

Ensure Safe Access of Nested Properties

When accessing content from replyMessage.content(), ensure that content is defined and has the expected structure before accessing nested properties like content.content.remoteAttachment. Adding type checks or null checks can prevent potential runtime errors due to undefined values.

components/Chat/Message/MessageReactionsList.tsx (1)

283-287: ⚠️ Potential issue

Reactivate Reaction Handling Logic in EmojiItem

The core logic for adding or removing reactions in the handlePress function is currently commented out. This prevents users from being able to interact with message reactions as intended. Please uncomment and verify this functionality to ensure that users can add or remove reactions.

components/Chat/Message/components/message-space-between-messages.tsx (1)

5-10: 🛠️ Refactor suggestion

Consider making this component more reusable.

The component is currently very specific to message spacing, but it could be made more reusable by accepting custom spacing values.

Consider this more flexible approach:

+type Props = {
+  spacing?: keyof typeof theme.spacing;
+};
+
 export const MessageSpaceBetweenMessages = memo(
-  function MessageSpaceBetweenMessages() {
+  function MessageSpaceBetweenMessages({ spacing = "4xs" }: Props) {
     const { theme } = useAppTheme();
-    return <VStack style={{ height: theme.spacing["4xs"] }} />;
+    return <VStack style={{ height: theme.spacing[spacing] }} />;
   }
 );

Alternatively, consider creating a more generic Spacer component that could be used throughout the app:

type SpacerProps = {
  size: keyof typeof theme.spacing;
  direction?: "vertical" | "horizontal";
};

export const Spacer = memo(function Spacer({ size, direction = "vertical" }: SpacerProps) {
  const { theme } = useAppTheme();
  return (
    <div
      style={{
        [direction === "vertical" ? "height" : "width"]: theme.spacing[size],
      }}
    />
  );
});
components/Chat/Message/components/message-container.tsx (1)

13-26: 🛠️ Refactor suggestion

Add accessibility attributes for screen readers.

Messages should be properly announced to screen readers. Consider adding appropriate ARIA attributes.

 <HStack
+  accessibilityRole="text"
+  accessibilityLabel={`Message ${fromMe ? 'sent' : 'received'}`}
   style={{
     flex: 1,
     alignItems: "flex-end",
     ...(fromMe
📝 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.

  return (
    <HStack
      accessibilityRole="text"
      accessibilityLabel={`Message ${fromMe ? 'sent' : 'received'}`}
      style={{
        // ...debugBorder("blue"),
        flex: 1,
        alignItems: "flex-end",
        ...(fromMe
          ? { justifyContent: "flex-end" }
          : { justifyContent: "flex-start" }),
      }}
    >
      {children}
    </HStack>
  );
components/Chat/Message/message-content-types/message-remote-attachment.tsx (2)

20-28: 🛠️ Refactor suggestion

Consider adding loading and error states

The component should handle loading and error states for remote attachments to improve user experience.

 return (
   <MessageLayout>
+    <ErrorBoundary fallback={<Text>Failed to load attachment</Text>}>
+      <Suspense fallback={<Loader />}>
         <RemoteAttachmentImage
           messageId={message.id}
           remoteMessageContent={content}
           fitAspectRatio
         />
+      </Suspense>
+    </ErrorBoundary>
   </MessageLayout>
 );

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


15-18: ⚠️ Potential issue

Implement error handling for string content

The TODO comment and returning null for string content might lead to silent failures. Consider implementing proper error handling or logging.

 if (typeof content === "string") {
-  // TODO
-  return null;
+  console.warn(`Unexpected string content in RemoteAttachment: ${content}`);
+  return <MessageLayout><Text>Invalid attachment format</Text></MessageLayout>;
 }

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

queries/useConversationWithPeerQuery.ts (2)

17-29: 🛠️ Refactor suggestion

Enhance error handling and logging.

The current implementation could benefit from better error handling and more specific logging.

     queryFn: async () => {
-      logger.info("[Crash Debug] queryFn fetching conversation with peer");
+      logger.info(`[Conversation] Fetching conversation for peer: ${peer}`);
       if (!peer) {
         return null;
       }
-      const conversation = await getConversationByPeerByAccount({
-        account,
-        peer,
-        includeSync: true,
-      });
-
-      return conversation;
+      try {
+        return await getConversationByPeerByAccount({
+          account,
+          peer,
+          includeSync: true,
+        });
+      } catch (error) {
+        logger.error(`[Conversation] Failed to fetch conversation: ${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.

    queryFn: async () => {
      logger.info(`[Conversation] Fetching conversation for peer: ${peer}`);
      if (!peer) {
        return null;
      }
      try {
        return await getConversationByPeerByAccount({
          account,
          peer,
          includeSync: true,
        });
      } catch (error) {
        logger.error(`[Conversation] Failed to fetch conversation: ${error}`);
        throw error;
      }
    },

14-17: ⚠️ Potential issue

Remove non-null assertion operator for safer type handling.

The non-null assertion (!) on peer in the query key could lead to runtime errors. Consider using a safer approach.

-    queryKey: conversationWithPeerQueryKey(account, peer!),
+    queryKey: conversationWithPeerQueryKey(account, peer ?? ''),

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

design-system/BlurView.tsx (1)

3-3: ⚠️ Potential issue

Remove unused FadeIn import.

The FadeIn animation is imported but never used in the component.

-import Animated, { AnimatedProps, FadeIn } from "react-native-reanimated";
+import Animated, { AnimatedProps } from "react-native-reanimated";
📝 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.

import Animated, { AnimatedProps } from "react-native-reanimated";
queries/useDmConstentStateQuery.ts (3)

14-14: ⚠️ Potential issue

Avoid non-null assertions in TypeScript

The non-null assertions (!) on topic and dmConversation could lead to runtime errors if these values are undefined. Consider implementing proper null checks or providing default values.

-  const { data: dmConversation } = useConversationQuery(account, topic!);
+  const { data: dmConversation } = useConversationQuery(account, topic);

   return useQuery({
-    queryKey: dmConsentQueryKey(account, topic!),
+    queryKey: topic ? dmConsentQueryKey(account, topic) : undefined,
     queryFn: () => dmConversation!.consentState(),

Also applies to: 18-18


18-20: ⚠️ Potential issue

Improve error handling for queryFn

The queryFn uses a non-null assertion and lacks error handling. Consider adding proper error handling and type checking.

-    queryFn: () => dmConversation!.consentState(),
+    queryFn: async () => {
+      if (!dmConversation) {
+        throw new Error('Conversation not found');
+      }
+      return dmConversation.consentState();
+    },
📝 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.

    queryFn: async () => {
      if (!dmConversation) {
        throw new Error('Conversation not found');
      }
      return dmConversation.consentState();
    },
    enabled: !!dmConversation && !!topic,
    initialData: dmConversation?.state,

46-54: 🛠️ Refactor suggestion

Add error handling to cancelDmConsentQuery

The cancelDmConsentQuery function should handle potential errors during query cancellation.

 export const cancelDmConsentQuery = async (args: {
   account: string;
   topic: ConversationTopic;
 }) => {
   const { account, topic } = args;
-  await queryClient.cancelQueries({
-    queryKey: dmConsentQueryKey(account, topic),
-  });
+  try {
+    await queryClient.cancelQueries({
+      queryKey: dmConsentQueryKey(account, topic),
+    });
+  } catch (error) {
+    console.error('Failed to cancel DM consent query:', 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.

export const cancelDmConsentQuery = async (args: {
  account: string;
  topic: ConversationTopic;
}) => {
  const { account, topic } = args;
  try {
    await queryClient.cancelQueries({
      queryKey: dmConsentQueryKey(account, topic),
    });
  } catch (error) {
    console.error('Failed to cancel DM consent query:', error);
    throw error;
  }
};
features/conversations/components/V3ConversationFromPeer.tsx (1)

1-2: 🛠️ Refactor suggestion

Update ActivityIndicator import to use new Loader component

According to the AI summary, ActivityIndicator is being replaced with the new Loader component across the codebase.

-import { useConversationWithPeerQuery } from "@/queries/useConversationWithPeerQuery";
-import ActivityIndicator from "@components/ActivityIndicator/ActivityIndicator";
+import { useConversationWithPeerQuery } from "@/queries/useConversationWithPeerQuery";
+import { Loader } from "@design-system/loader";
📝 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.

import { useConversationWithPeerQuery } from "@/queries/useConversationWithPeerQuery";
import { Loader } from "@design-system/loader";
queries/useConversationQuery.ts (1)

17-27: 🛠️ Refactor suggestion

Consider adding error handling for undefined topic

While the code uses non-null assertion (topic!), it would be safer to handle undefined topics explicitly since the function accepts undefined as a valid type.

 export const useConversationQuery = (
   account: string,
   topic: ConversationTopic | undefined,
   options?: Partial<UseQueryOptions<ConversationQueryData | null | undefined>>
 ) => {
+  if (!topic) {
+    return {
+      data: undefined,
+      isLoading: false,
+      error: new Error('Topic is required')
+    };
+  }
   return useQuery({
     ...options,
-    queryKey: conversationQueryKey(account, topic!),
-    queryFn: () => getConversation(account, topic!),
+    queryKey: conversationQueryKey(account, topic),
+    queryFn: () => getConversation(account, topic),
     enabled: !!topic,
   });
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export const useConversationQuery = (
  account: string,
  topic: ConversationTopic | undefined,
  options?: Partial<UseQueryOptions<ConversationQueryData | null | undefined>>
) => {
  if (!topic) {
    return {
      data: undefined,
      isLoading: false,
      error: new Error('Topic is required')
    };
  }
  return useQuery({
    ...options,
    queryKey: conversationQueryKey(account, topic),
    queryFn: () => getConversation(account, topic),
    enabled: !!topic,
  });
};
components/Chat/ConsentPopup/group-consent-popup.tsx (2)

23-23: ⚠️ Potential issue

Avoid non-null assertion on currentAccount

The non-null assertion (!) on useCurrentAccount() could lead to runtime errors if the account is not available. Consider handling the null case gracefully.

-  const currentAccount = useCurrentAccount()!;
+  const currentAccount = useCurrentAccount();
+  if (!currentAccount) {
+    return null; // or handle the no-account case appropriately
+  }
📝 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 currentAccount = useCurrentAccount();
  if (!currentAccount) {
    return null; // or handle the no-account case appropriately
  }

46-55: ⚠️ Potential issue

Inconsistent navigation behavior between accept and block actions

The onBlock action navigates on success while onAccept doesn't handle navigation. This could lead to inconsistent UX.

   const onAccept = useCallback(async () => {
     try {
       await allowGroup({
         includeCreator: false,
         includeAddedBy: false,
       });
+      navigation.pop();
     } catch (error) {
       captureErrorWithToast(error);
     }
-  }, [allowGroup]);
+  }, [allowGroup, navigation]);
📝 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 onAccept = useCallback(async () => {
    try {
      await allowGroup({
        includeCreator: false,
        includeAddedBy: false,
      });
      navigation.pop();
    } catch (error) {
      captureErrorWithToast(error);
    }
  }, [allowGroup, navigation]);
components/Chat/Message/message-utils.tsx (1)

151-217: 🛠️ Refactor suggestion

Consider refactoring message content extraction for better maintainability

The getMessageStringContent function is quite long and handles multiple message types. Consider breaking it down into smaller, type-specific functions.

+function getReplyMessageContent(content: ReplyContent): string {
+  if (content.content.text) return content.content.text;
+  if (content.content.reply?.content.text) return content.content.reply.content.text;
+  if (content.content.attachment?.filename) return content.content.attachment.filename;
+  if (content.content.remoteAttachment?.url) return content.content.remoteAttachment.url;
+  if (content.content.groupUpdated) return "Group updated";
+  return "";
+}
+
 export function getMessageStringContent(
   message: DecodedMessageWithCodecsType
 ): string | undefined {
   // ... existing type checks ...
   
   if (isReplyMessage(message)) {
-    const content = message.content() as ReplyContent;
-    if (content.content.text) {
-      return content.content.text;
-    }
-    // ... other reply content checks ...
+    return getReplyMessageContent(message.content() as ReplyContent);
   }
   
   // ... rest of the function ...
 }

This refactoring would:

  1. Improve code readability
  2. Make it easier to test individual message type handling
  3. Reduce the cognitive complexity of the main function

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

containers/GroupScreenMembersTable.tsx (1)

45-45: ⚠️ Potential issue

Consider safer null handling for topic fallback

The current implementation uses non-null assertion (!), which could lead to runtime errors if both topic and group?.topic are undefined.

Consider this safer implementation:

-    } = useGroupMembers((topic ?? group?.topic)!);
+    } = useGroupMembers(topic ?? group?.topic ?? '');
     const { data: groupPermissionPolicy } = useGroupPermissionPolicyQuery(
       currentAccount,
-      (topic ?? group?.topic)!
+      topic ?? group?.topic ?? ''
     );

Alternatively, add runtime checks:

if (!topic && !group?.topic) {
  logger.error('No topic available for group members');
  return null;
}

Also applies to: 47-48

screens/GroupInvite.tsx (1)

61-61: ⚠️ Potential issue

Remove unsafe non-null assertion on optional newGroup

The non-null assertion on newGroup?.topic! is unsafe as newGroup is initialized as undefined and only set after successful group operations.

Consider this safer implementation:

-  const { allowGroup } = useGroupConsent(newGroup?.topic!);
+  const { allowGroup } = useGroupConsent(newGroup?.topic ?? '');

Also, consider adding a guard clause:

if (!newGroup?.topic) {
  logger.warn('No topic available for group consent');
  return null;
}
components/GroupAvatar.tsx (1)

43-43: ⚠️ Potential issue

Resolve inconsistency between prop type and usage

The topic prop is marked as optional in GroupAvatarProps, but used with a non-null assertion in useGroupMembers. This creates a type-safety gap.

Consider one of these approaches:

  1. If topic should be required:
-  topic?: ConversationTopic;
+  topic: ConversationTopic;
  1. If topic can be optional, handle it safely:
-    topic!,
+    topic ?? '',

Also, the enabled condition already checks for !!topic, making the non-null assertion redundant:

enabled: !!topic && !pendingGroupMembers,

Also applies to: 205-213

screens/NewConversation/NewConversation.tsx (1)

60-60: 🛠️ Refactor suggestion

Replace non-null assertion with proper type guard

The non-null assertion operator (!) bypasses TypeScript's type checking. While runtime checks exist elsewhere in the code, it's safer to handle the optional parameter explicitly.

Consider this safer approach:

- route.params?.addingToGroupTopic!
+ route.params?.addingToGroupTopic ?? ''

Then update the useGroupQuery hook to handle empty string cases appropriately.

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

theme.spacing.xs +
// Account for safe area at the bottom of the screen
(safeAreaInsets?.bottom || 0);
console.log("items:", items);
Copy link
Contributor

Choose a reason for hiding this comment

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

😄

@alexrisch alexrisch force-pushed the ts/message-refactoring-attachments branch 2 times, most recently from b84d2c3 to b425fec Compare December 4, 2024 23:19
Base automatically changed from ts/message-refactoring-attachments to release/3.0.0 December 5, 2024 14:54
@thierryskoda
Copy link
Collaborator Author

Closed and replaced with #1314

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants