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

Mark conversation as read when entering chat #1311

Merged
merged 7 commits into from
Dec 9, 2024

Conversation

lourou
Copy link
Member

@lourou lourou commented Dec 5, 2024

Screencast for both DM and group convos:

CleanShot 2024-12-07 at 09 50 08

Closes #1307

Summary by CodeRabbit

  • New Features

    • Enhanced message handling in conversations with improved unread status management.
    • New hooks introduced for tracking unread messages and toggling read status.
    • Added functionality for deleting and restoring conversations with user consent.
    • Context menu actions updated to include options for marking messages as read/unread.
  • Bug Fixes

    • Streamlined logic for determining unread message status to ensure accurate updates.
  • Chores

    • Removed deprecated function for unread message display, simplifying the codebase.
  • Documentation

    • Added comments to clarify the purpose of new functionality related to unread message handling.

Copy link
Contributor

coderabbitai bot commented Dec 5, 2024

Warning

Rate limit exceeded

@lourou has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 20 minutes and 29 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e5de05a and 8cfa15b.

Walkthrough

The changes in this pull request introduce new hooks and modify existing functionality within the conversation handling components. The V3Conversation.tsx component now utilizes useConversationIsUnread and useToggleReadStatus hooks to manage the read status of conversations more effectively. The useMessageIsUnread hook has been updated to enhance its logic and integration with the current account context. Additionally, a function related to unread message indicators has been removed. Logging has been added to the useToggleReadStatus hook for debugging purposes.

Changes

File Path Change Summary
components/Conversation/V3Conversation.tsx Added hooks: useConversationIsUnread, useToggleReadStatus; modified logic for unread messages.
features/conversation-list/hooks/useMessageIsUnread.ts Updated logic to clarify unread status determination; removed unused import.
features/conversation-list/hooks/useToggleReadStatus.ts Added readUntil property for enhanced data structure; logic remains unchanged.
utils/conversation/showUnreadOnConversation.ts Removed the showUnreadOnConversation function.
components/PinnedConversations/PinnedV3DMConversation.tsx Simplified isUnread calculation; updated context menu actions; optimized rendering with hooks.
components/PinnedConversations/PinnedV3GroupConversation.tsx Simplified parameters for useConversationIsUnread; enhanced context menu functionality.
components/V3DMListItem.tsx Updated isUnread handling; modified context menu actions; optimized user interactions.
components/V3GroupConversationListItem.tsx Enhanced delete/restore logic; updated context menu actions; modified unread status checks.

Assessment against linked issues

Objective Addressed Explanation
Conversation is not marked as read when entering chat (#1307)

Possibly related PRs

Suggested reviewers

  • thierryskoda
  • technoplato

Poem

In a chat where messages flow,
Unread tales begin to grow.
With hooks that toggle, read or not,
A clearer path, we’ve surely sought.
So hop along, let’s mark the day,
For every chat, we find our way! 🐇✨


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.

@lourou lourou changed the base branch from main to release/3.0.0 December 5, 2024 16:59
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.

Actionable comments posted: 22

🧹 Outside diff range and nitpick comments (18)
components/Banner/AnimatedBanner.tsx (1)

Line range hint 24-84: Consider enhancing component configurability.

The component implementation is solid, but consider these improvements for better flexibility:

  1. Make animation duration and easing configurable via props
  2. Allow customization of zIndex through props instead of hardcoding to 1000
  3. Consider making VERTICAL_MARGIN configurable

Example implementation:

 type AnimatedBannerProps = {
   title: string;
   description: string;
   cta?: string;
   onButtonPress?: () => void;
   onDismiss?: () => void;
   style?: StyleProp<ViewStyle>;
+  animationDuration?: number;
+  animationEasing?: Animated.EasingFunction;
+  zIndex?: number;
+  verticalMargin?: number;
 };

-const VERTICAL_MARGIN = Margins.default;
+const DEFAULT_VERTICAL_MARGIN = Margins.default;
+const DEFAULT_ANIMATION_DURATION = 200;
+const DEFAULT_Z_INDEX = 1000;

 const AnimatedBanner: React.FC<AnimatedBannerProps> = React.memo(({
+  animationDuration = DEFAULT_ANIMATION_DURATION,
+  animationEasing = Easing.bezier(0.7, 0.0, 1, 1),
+  zIndex = DEFAULT_Z_INDEX,
+  verticalMargin = DEFAULT_VERTICAL_MARGIN,
+  ...props
 }) => {
components/Chat/Frame/urlProtocols.ts (1)

1-6: LGTM! Consider adding TypeScript types for better type safety.

The implementation correctly creates a Set of unique URL protocols. However, adding TypeScript types would improve code reliability.

Consider applying these changes:

-import config from "../../../config";
+interface Config {
+  scheme: string;
+  framesAllowedSchemes: string[];
+}
+import config from "../../../config" as Config;
components/AndroidBackAction.tsx (1)

4-4: Consider documenting color scheme behavior

The component correctly handles dark/light mode via useColorScheme and textSecondaryColor utility. Consider adding a brief comment explaining the color scheme behavior for future maintainability.

 import { useColorScheme } from "react-native";
 
 export default function AndroidBackAction({
   navigation,
 }: {
   navigation: NativeStackNavigationProp<any>;
 }) {
+  // Adapts back button color based on current color scheme
   const colorScheme = useColorScheme();
   return (
     <HeaderBackButton
       onPress={navigation.goBack}
       canGoBack={navigation.canGoBack()}
       style={{ marginLeft: -3 }}
       tintColor={textSecondaryColor(colorScheme)}
     />
   );
 }

Also applies to: 11-18

components/Chat/ChatNullState.tsx (1)

30-34: Consider adding proper typing for navigation props

The navigation and route props are currently typed as any. Consider using proper types from the navigation library for better type safety and developer experience.

+import { StackNavigationProp } from '@react-navigation/stack';
+import { RouteProp } from '@react-navigation/native';
+import { RootStackParamList } from '../../navigation/types';

 type ChatNullStateProps = {
   currentAccount: string;
-  navigation: any;
-  route: any;
+  navigation: StackNavigationProp<RootStackParamList>;
+  route: RouteProp<RootStackParamList>;
 };
components/Chat/Frame/FramePreview.tsx (1)

3-3: Address the TODO comment

The TODO comment indicates that this file should be deleted after refactoring is complete. To maintain a clean codebase, please remove this file if it's no longer needed.

Do you need assistance in removing this file or completing the refactoring process?

components/Chat/ChatDumb.tsx (1)

219-241: Confirm whether the commented-out Chat Input code should be included

The code responsible for rendering the chat input area is currently commented out. If the chat input is intended to be part of this component, consider uncommenting this section. Otherwise, if it's no longer needed, it might be cleaner to remove it entirely to keep the codebase tidy.

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

116-140: Reuse AttachmentContainer instead of defining AttachmentPreviewContainer

The AttachmentPreviewContainer component provides styling similar to the AttachmentContainer component introduced elsewhere. To adhere to the DRY principle and improve maintainability, consider reusing AttachmentContainer to avoid code duplication.

Apply this diff to refactor the code:

-import { IVStackProps, VStack } from "@design-system/VStack";
+import { AttachmentContainer } from "@/components/Chat/Attachment/attachment-container";

-const AttachmentPreviewContainer = memo(function AttachmentPreviewContainer(
-  props: IVStackProps
-) {
-  const { style, ...rest } = props;
-
-  const { theme } = useAppTheme();
-
-  return (
-    <VStack
-      style={[
-        {
-          overflow: "hidden",
-          borderRadius: theme.borderRadius.sm,
-          width: "100%",
-          justifyContent: "center",
-          alignItems: "center",
-          backgroundColor: theme.colors.fill.tertiary,
-          aspectRatio: 1.5, // Default aspect ratio for attachments
-        },
-        style,
-      ]}
-      {...rest}
-    />
-  );
-});
+const AttachmentPreviewContainer = AttachmentContainer;

104-111: Add accessibility labels to the Image component

To improve accessibility for users utilizing screen readers, add an accessibilityLabel or accessible prop to the Image component. This ensures that the image content is properly described.

Apply this diff to include an accessibility label:

<Image
  source={{ uri: attachment.mediaURL }}
  contentFit="cover"
  style={{
    width: "100%",
    height: "100%",
  }}
+ accessible={true}
+ accessibilityLabel={translate("attachment_image_accessibility_label")}
>

Ensure that the translation key "attachment_image_accessibility_label" is added to the localization files with an appropriate description.

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

87-89: Use localized error messages

Consider using the translate function for error messages to support internationalization.

Apply this diff:

                 showSnackbar({
                   type: "error",
-                  message: `Error consenting`,
+                  message: translate("error_consenting"),
                 });

103-104: Use localized error messages

Consider using the translate function for error messages to support internationalization.

Apply this diff:

         captureErrorWithToast(ensureError(error), {
-          message: `Error consenting`,
+          message: translate("error_consenting"),
         });
components/Chat/ConsentPopup/consent-popup.design-system.tsx (1)

8-12: Pass the 'style' prop to the Button component and remove unused variable

In ConsentPopupButton, the style prop is accepted but not passed to the Button component, and the theme variable is declared but not used. To allow styling the button and clean up unused code, pass the style prop down and remove the unused variable.

Apply this diff:

 export function ConsentPopupButton({ style, ...rest }: IButtonProps) {
-  const { theme } = useAppTheme();

-  return <Button {...rest} />;
+  return <Button style={style} {...rest} />;
 }
android/gradle.properties (1)

53-54: Consider environment-specific network inspector configuration

The network inspector is enabled globally, which might affect release builds.

Consider moving this configuration to a development-specific properties file or using a build type condition:

-# Enable network inspector
-EX_DEV_CLIENT_NETWORK_INSPECTOR=true
+# Enable network inspector (dev only)
+dev.EX_DEV_CLIENT_NETWORK_INSPECTOR=true
android/app/src/preview/AndroidManifest.xml (1)

1-31: Consider extracting common configurations

The preview and production manifests share identical structure and paths.

Consider:

  1. Using manifest placeholders for environment-specific values
  2. Creating a base manifest template
  3. Using manifest merging to reduce duplication

Example approach:

<!-- base/AndroidManifest.xml -->
<manifest ...>
    <application ...>
        <activity ...>
            <intent-filter>
                <data android:scheme="${appScheme}"/>
                <data android:scheme="${appPackageScheme}"/>
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <data android:host="${appHost}" .../>
                <!-- other paths -->
            </intent-filter>
        </activity>
    </application>
</manifest>

Then in build.gradle:

android {
    defaultConfig {
        manifestPlaceholders = [
            appScheme: "converse",
            appPackageScheme: "com.converse.prod",
            appHost: "getconverse.app"
        ]
    }
    
    productFlavors {
        preview {
            manifestPlaceholders = [
                appScheme: "converse-preview",
                appPackageScheme: "com.converse.preview",
                appHost: "preview.getconverse.app"
            ]
        }
    }
}
adr/adr.001.folder and file structure/example composite component structure.md (1)

3-3: Fix typo in documentation

"pressented" should be "presented"

README.md (2)

43-50: Improve formatting and clarity of web limitations note

The web limitations section needs some formatting improvements:

### Please Note

-Currently Groups and V3 Identity is not supported on Web at the SDK layer, but is actively being worked on by the team
+Currently, Groups and V3 Identity are not supported on Web at the SDK layer, but are actively being worked on by the team.

-Until then Converse web will only show 1 to 1 conversations and the majority of testing and development are native app focused.
+Until then, Converse web will only show one-on-one conversations, and the majority of testing and development are native app focused.

-Web support is an end goal and the team is happy to fix any issues that are reported
+Web support is an end goal, and the team is committed to resolving any reported issues.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~44-~44: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...uilding the App - Web ### Please Note Currently Groups and V3 Identity is not supported...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[typographical] ~46-~46: It seems that a comma is missing after this introductory phrase.
Context: ...s actively being worked on by the team Until then Converse web will only show 1 to 1 conv...

(SINCE_THEN_COMMA)


[uncategorized] ~47-~47: It appears that hyphens are missing.
Context: ... Until then Converse web will only show 1 to 1 conversations and the majority of testi...

(ONE_ON_ONE_HYPHEN)


[style] ~49-~49: Consider using a different verb for a more formal wording.
Context: ...is an end goal and the team is happy to fix any issues that are reported ### Insta...

(FIX_RESOLVE)

🪛 Markdownlint (0.35.0)

43-43: Expected: h2; Actual: h3
Heading levels should only increment by one level at a time

(MD001, heading-increment)


81-101: LGTM: Added comprehensive testing documentation

The new sections for Jest and Performance testing provide clear instructions for developers.

Consider adding examples of expected .env variables for completeness.

🧰 Tools
🪛 LanguageTool

[style] ~94-~94: Consider shortening or rephrasing this to strengthen your wording.
Context: ...ests sh yarn test:perf:baseline Make changes to the code to see the performance impact ...

(MAKE_CHANGES)

adr/adr.002.architecture for business logic and dependencies - join group/adr.002.architecture-poc-for-business-logic-and-dependencies-group-joining.md (1)

102-116: Enhance the Consequences section with additional considerations

Consider adding the following to strengthen the ADR:

  1. Specific success metrics to measure the impact of the refactoring
  2. Clear rollback strategy in case of unforeseen issues
  3. Performance impact analysis of introducing XState
adr/adr.001.folder and file structure/adr.001.folder and file structure.md (1)

286-286: Consider adding guidance for cross-feature interactions

The ADR would benefit from additional sections covering:

  1. How to handle dependencies between features
  2. Strategy for feature-specific configuration management
  3. Guidelines for sharing types across features

Example structure:

## Cross-Feature Dependencies

- Guidelines for importing from other features
- Strategies to minimize coupling
- Handling shared types and interfaces

## Feature-Specific Configuration

- Location of feature-specific config files
- Environment variable management
- Feature flag implementation
🛑 Comments failed to post (22)
components/Chat/Frame/urlProtocols.ts (1)

3-6: 🛠️ Refactor suggestion

Add validation for config properties.

The code assumes that config properties exist and are properly formatted, but this should be validated.

Consider adding validation:

+const validateScheme = (scheme: string): string => {
+  if (!scheme || typeof scheme !== 'string') {
+    throw new Error('Invalid scheme format in config');
+  }
+  return scheme.endsWith(':') ? scheme : `${scheme}:`;
+};

 export const AUTHORIZED_URL_PROTOCOLS = new Set([
-  `${config.scheme}:`,
-  ...config.framesAllowedSchemes.map((s) => `${s}:`),
+  validateScheme(config.scheme),
+  ...(config.framesAllowedSchemes || []).map(validateScheme),
 ]);
📝 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 validateScheme = (scheme: string): string => {
  if (!scheme || typeof scheme !== 'string') {
    throw new Error('Invalid scheme format in config');
  }
  return scheme.endsWith(':') ? scheme : `${scheme}:`;
};

export const AUTHORIZED_URL_PROTOCOLS = new Set([
  validateScheme(config.scheme),
  ...(config.framesAllowedSchemes || []).map(validateScheme),
]);
android/app/src/main/google-services.json (1)

21-25: ⚠️ Potential issue

CRITICAL: Remove sensitive API key from version control

The Google Cloud Platform API key is exposed in the repository. This poses a significant security risk as it could be misused to access your Google Cloud services.

Recommended actions:

  1. Immediately rotate/revoke this API key in Google Cloud Console
  2. Move sensitive credentials to environment variables or secure credential management systems
  3. Add this file to .gitignore
  4. Use a template file (e.g., google-services.json.template) with placeholder values for version control

Example template approach:

{
  "api_key": [
    {
      "current_key": "${ANDROID_GCP_API_KEY}"
    }
  ]
}
🧰 Tools
🪛 Gitleaks (8.21.2)

23-23: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

components/ActivityIndicator/ActivityIndicator.tsx (1)

1-6: 💡 Codebase verification

This change is unrelated to the PR's objective and should be in a separate PR

The evidence shows this is an unrelated change:

  • The PR description "WIP read/unread" indicates focus on read/unread conversation functionality
  • The ActivityIndicator to Loader migration appears to be a design system upgrade
  • While the component is used in chat-related features (V3ConversationFromPeer.tsx still uses ActivityIndicator), this specific change is about component deprecation and not about read/unread functionality

This change should be moved to a separate PR focused on design system component migrations to maintain clear change scope and traceability.

🔗 Analysis chain

Verify relevance to PR objectives.

This component change appears unrelated to the PR's stated objective of "Mark conversation as read when entering chat". Please clarify how this change contributes to the PR's goal.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if this component is used in chat-related features
# to understand its relevance to marking conversations as read

# Search for ActivityIndicator usage in chat-related files
rg -l "ActivityIndicator|Loader" | rg -i "chat|conversation"

# Search for any recent changes to chat-related files that might explain this change
git diff HEAD~1 -- "**/chat/**" "**/conversation/**"

Length of output: 531


Script:

#!/bin/bash
# Let's check the actual usage of ActivityIndicator in these files
# and see if there are any changes related to loading states in chat features

# Check ActivityIndicator/Loader usage in chat and conversation files
rg -A 5 "ActivityIndicator|Loader" components/Chat/Attachment/attachment-loading.tsx components/Chat/ChatPlaceholder/ChatPlaceholder.tsx features/conversations/components/V3ConversationFromPeer.tsx features/conversation/dm-conversation.screen.tsx

# Check if there are any pending migrations from ActivityIndicator to Loader
# in chat-related files that might explain this change
rg -l "@design-system/loader" components/Chat features/conversation features/conversations screens/NewConversation

# Look at the PR description to understand the context
git show --format=%B -s HEAD

Length of output: 4578

android/app/src/prod/google-services.json (1)

21-25: ⚠️ Potential issue

⚠️ Critical: Remove API key from version control

The Google Cloud Platform API key should not be committed to version control as it poses a significant security risk. This could lead to unauthorized access to your Google Cloud services.

Please follow these steps to secure your configuration:

  1. Remove the API key from the repository
  2. Rotate the exposed API key immediately in Google Cloud Console
  3. Use environment variables or a secure secret management system
  4. Add google-services.json to .gitignore

Would you like assistance in implementing a secure configuration management solution?

🧰 Tools
🪛 Gitleaks (8.21.2)

23-23: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

components/Chat/Frame/FrameBottom.tsx (1)

71-73: 🛠️ Refactor suggestion

Consider adding a platform check for haptics support.

The unconditional haptic feedback might cause issues on platforms where haptics are not supported.

Consider wrapping the haptic call with a platform check:

-Haptics.impactAsync();
+if (Platform.OS !== 'web') {
+  Haptics.impactAsync();
+}
📝 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 (Platform.OS !== 'web') {
                    Haptics.impactAsync();
                  }
                  onButtonPress(button);
                }}
components/Chat/Frame/FramePreview.tsx (1)

7-415: 🛠️ Refactor suggestion

Remove large blocks of commented-out code

The code from lines 7 to 415 is entirely commented out. It's best practice to remove unused code rather than leaving it commented out to improve readability and maintainability. Version control systems can help retrieve previous versions if necessary.

components/Chat/ChatDumb.tsx (2)

117-122: 🛠️ Refactor suggestion

Ensure chatInputHeight.value is updated to reflect dynamic input height

The shared value chatInputHeight is used in calculating chatInputDisplayedHeight, which influences the padding of the chat content. Currently, chatInputHeight.value is initialized to zero and not updated in the provided code. If the chat input height changes dynamically, make sure to update chatInputHeight.value accordingly to maintain the correct layout.


190-215: ⚠️ Potential issue

Assign messageListRef to the ref prop of ReanimatedFlashList to enable scrolling

The messageListRef is used in the scrollToMessage function to control scrolling of the chat messages. However, it's not assigned to the ref prop of ReanimatedFlashList, so messageListRef.current will be undefined, and the scrolling functionality will not work as intended.

Apply this diff to assign messageListRef to the ref prop:

 <ReanimatedFlashList
   contentContainerStyle={styles.chat}
   data={items}
+  ref={messageListRef}
   refreshing={refreshing}
   extraData={extraData}
   renderItem={renderItem}
   onLayout={handleOnLayout}
   keyboardDismissMode="interactive"
   automaticallyAdjustContentInsets={false}
   contentInsetAdjustmentBehavior="never"
   inverted
   keyExtractor={keyExtractor}
   getItemType={getItemType}
   keyboardShouldPersistTaps="handled"
   estimatedItemSize={34}
   showsVerticalScrollIndicator={Platform.OS === "ios"}
   pointerEvents="auto"
   ListFooterComponent={ListFooterComponent}
 />
📝 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.

          <ReanimatedFlashList
            contentContainerStyle={styles.chat}
            data={items}
            ref={messageListRef}
            refreshing={refreshing}
            extraData={extraData}
            renderItem={renderItem}
            onLayout={handleOnLayout}
            keyboardDismissMode="interactive"
            automaticallyAdjustContentInsets={false}
            contentInsetAdjustmentBehavior="never"
            // Causes a glitch on Android, no sure we need it for now
            // maintainVisibleContentPosition={{
            //   minIndexForVisible: 0,
            //   autoscrollToTopThreshold: 100,
            // }}
            // estimatedListSize={Dimensions.get("screen")}
            inverted
            keyExtractor={keyExtractor}
            getItemType={getItemType}
            keyboardShouldPersistTaps="handled"
            estimatedItemSize={34}
            // Size glitch on Android
            showsVerticalScrollIndicator={Platform.OS === "ios"}
            pointerEvents="auto"
            ListFooterComponent={ListFooterComponent}
          />
components/Chat/Attachment/remote-attachment-image.tsx (2)

77-81: ⚠️ Potential issue

Implement the onPress handler to open attachments in the webview

The onPress handler for unsupported media types is currently empty. To enhance user experience, implement the logic to open the attachment in a webview or the default browser when the user taps on the link.


157-157: ⚠️ Potential issue

Ensure getCurrentAccount() cannot return null to prevent runtime errors

In fetchAttachment, getCurrentAccount() is called with a non-null assertion (!). If there's any possibility that getCurrentAccount() could return null or undefined, this may lead to runtime exceptions. Verify that an account is always available when this function is called, or add appropriate null checks.

Consider modifying the code to handle the potential null case:

- account: getCurrentAccount()!,
+ const currentAccount = getCurrentAccount();
+ if (!currentAccount) {
+   throw new Error("No current account available");
+ }
+ account: currentAccount,
📝 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 = getCurrentAccount();
      if (!currentAccount) {
        throw new Error("No current account available");
      }
      account: currentAccount,
components/Chat/ChatGroupUpdatedMessage.tsx (3)

79-117: 🛠️ Refactor suggestion

Refactor to eliminate code duplication between ChatGroupMemberLeft and ChatGroupMemberJoined

The ChatGroupMemberLeft and ChatGroupMemberJoined components share significant code duplication. Consider abstracting the shared logic into a single component or a helper function, passing in props to handle the differences such as the translation key and event type.

For example, create a generic ChatGroupMemberUpdate component:

type IChatGroupMemberUpdateProps = {
  inboxId: InboxId;
  eventType: 'joined' | 'left';
};

function ChatGroupMemberUpdate({ inboxId, eventType }: IChatGroupMemberUpdateProps) {
  // Shared logic...
  const translationKey = eventType === 'joined' ? 'group_member_joined' : 'group_member_left';
  // Render logic...
}

Then replace ChatGroupMemberLeft and ChatGroupMemberJoined with this new component.

Also applies to: 125-165


16-16: ⚠️ Potential issue

Correct the typo in the import statement

There's a typo in the import statement. The correct type name is GroupUpdatedMetadataEntry.

Apply this diff to fix the typo:

- GroupUpdatedMetadatEntry,
+ GroupUpdatedMetadataEntry,

Ensure that all usages of GroupUpdatedMetadataEntry are updated accordingly.

📝 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.

  GroupUpdatedMetadataEntry,

115-115: ⚠️ Potential issue

Incorrect translation key in ChatGroupMemberLeft component

In the ChatGroupMemberLeft component, the message uses the translation key for a member joining the group. It should use translate("group_member_left") to indicate that a member has left.

Apply this diff to correct the translation key:

<ChatGroupUpdateText>
- {translate("group_member_joined")}
+ {translate("group_member_left")}
</ChatGroupUpdateText>

Ensure the translation key "group_member_left" exists in the localization files.

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

components/Chat/ActionButton.tsx (1)

15-15: 💡 Codebase verification

Update required: ActionButton usages need to be modified to use IPicto type

The search results show several instances where ActionButton is being used with string literals for the picto prop, which needs to be updated to use the new IPicto type:

  • screens/ShareProfile.tsx: Uses picto="xmark"
  • components/Chat/Message/Message.tsx: Uses picto="arrowshape.turn.up.left" (in commented code)
  • components/Chat/Transaction/SendMoneyButton.tsx: Uses picto="dollarsign" (in commented code)
  • components/Chat/Frame/FramePreview.tsx: Uses picto="square.and.arrow.up" (in commented code)
🔗 Analysis chain

Verify all usages of ActionButton are updated to pass IPicto type for picto

The picto prop type in ChatActionProps has been changed from string to IPicto. Ensure that all components using ActionButton are updated to pass an IPicto type to prevent type errors.

Run the following script to find usages of ActionButton and check for picto prop types:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of ActionButton and check if picto prop is correctly typed

# Find all files importing ActionButton
fd --type f --extension tsx | xargs grep -n 'import.*ActionButton'

# Search for ActionButton component usage
rg '<ActionButton' --type tsx -A 5

# Check for picto prop being passed as a string literal
rg '<ActionButton[^>]*picto=[\'"].*[\'"]' --type tsx

# Verify that picto prop is passed an IPicto variable
rg '<ActionButton' --type tsx -A 5 | rg 'picto={' -A 1

Length of output: 523


Script:

#!/bin/bash
# Let's try a different approach using ripgrep with proper file type specification

# Find all files importing ActionButton
rg "import.*ActionButton" -t typescript -t typescriptreact

# Search for ActionButton component usage with context
rg "<ActionButton" -t typescript -t typescriptreact -A 5

# Check for picto prop being passed as a string literal
rg "<ActionButton[^>]*picto=['\"].*['\"]" -t typescript -t typescriptreact

# Verify that picto prop is passed an IPicto variable
rg "<ActionButton.*picto=\{.*\}" -t typescript -t typescriptreact

Length of output: 408


Script:

#!/bin/bash
# Let's try without specifying file types and use basic pattern matching

# Find imports of ActionButton
rg "import.*ActionButton"

# Find all ActionButton usages with surrounding context
rg "<ActionButton" -A 5

# Look for picto prop usage
rg "picto=" --context 2 | rg -B 2 "ActionButton"

Length of output: 3126

App.tsx (3)

1-1: ⚠️ Potential issue

Avoid importing expo-dev-client in production code

Importing "expo-dev-client" is intended for development purposes and should not be included in production builds, as it can increase app size and potentially expose development tools. Consider conditionally importing it only in development environments or removing it from production code.


88-96: ⚠️ Potential issue

Ensure authStatus updates when currentAccount changes

The current useEffect runs only once due to the empty dependency array [], so if currentAccount changes after the component mounts, authStatus will not update accordingly. Consider subscribing to currentAccount changes by using the hook version of useAccountsStore and including currentAccount in the dependency array.

Apply this diff to fix the issue:

- useEffect(() => {
-   const currentAccount = useAccountsStore.getState().currentAccount;
+ const currentAccount = useAccountsStore(state => state.currentAccount);
+ useEffect(() => {
    if (currentAccount && currentAccount !== TEMPORARY_ACCOUNT_NAME) {
      setAuthStatus("signedIn");
    } else {
      setAuthStatus("signedOut");
    }
- }, []);
+ }, [currentAccount]);
📝 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.

  // For now we use persit with zustand to get the accounts when the app launch so here is okay to see if we're logged in or not
  const currentAccount = useAccountsStore(state => state.currentAccount);
  useEffect(() => {
    if (currentAccount && currentAccount !== TEMPORARY_ACCOUNT_NAME) {
      setAuthStatus("signedIn");
    } else {
      setAuthStatus("signedOut");
    }
  }, [currentAccount]);

62-62: ⚠️ Potential issue

Move xmtpEngine.start() inside a useEffect hook

Calling xmtpEngine.start() at the module level can cause unintended side effects during module initialization and may execute before the app is ready. It's better to place it inside a useEffect hook within the App component to ensure it runs after the component mounts.

Apply this diff to move the call inside the App component:

// Remove the module-level invocation
- xmtpEngine.start();

...

// Inside the App component
+ useEffect(() => {
+   xmtpEngine.start();
+ }, []);

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

android/app/src/preview/google-services.json (1)

21-25: ⚠️ Potential issue

Critical: Remove API key from version control.

The exposed Google Cloud Platform API key poses a security risk. API keys should never be committed to version control.

Please:

  1. Remove this API key immediately and revoke it
  2. Use environment variables or a secure secret management system
  3. Update the documentation to guide developers on obtaining and configuring their own API keys for development

Example approach using environment variables:

  1. Remove the API key from the file
  2. Use a placeholder:
  "api_key": [
    {
-      "current_key": "AIzaSyBLyJ66tj4-ej4Cq2BHa-EJhHNTNWp8bFE"
+      "current_key": "${GOOGLE_API_KEY}"
    }
  ],
  1. Add the file to .gitignore
  2. Provide a template file (e.g., google-services.json.template) without sensitive data

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

🧰 Tools
🪛 Gitleaks (8.21.2)

23-23: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

android/app/src/main/java/com/converse/MainActivity.kt (1)

1-1: 💡 Codebase verification

Package name change requires updates to deep linking configuration

The verification reveals that the deep linking configuration in AndroidManifest.xml still uses the old package name schemes:

<data android:scheme="converse-dev"/>
<data android:scheme="com.converse.dev"/>

Additionally, the config.ts file shows that the bundleId is still set to "com.converse.dev" in the development environment configuration, which is inconsistent with the package name change to "com.converse" in MainActivity.kt.

  • Update deep linking schemes in android/app/src/main/AndroidManifest.xml
  • Update bundleId in config.ts to match the new package name
  • Ensure the applicationId in android/app/build.gradle is aligned with the new package name
🔗 Analysis chain

Verify impact of package name change on deep linking

The package name change from com.converse.dev to com.converse could affect deep linking to chat conversations. Please ensure all deep link handlers are updated accordingly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for deep link handlers and URL schemes that might need updating
rg -l "com\.converse\.dev" .

Length of output: 486


Script:

#!/bin/bash
# Let's check the actual content of these files to understand the deep linking configuration
echo "=== Checking AndroidManifest.xml ==="
cat android/app/src/main/AndroidManifest.xml

echo -e "\n=== Checking config.ts ==="
cat config.ts

echo -e "\n=== Checking build.gradle ==="
cat android/app/build.gradle

Length of output: 21503

android/app/src/prod/AndroidManifest.xml (2)

14-28: 💡 Codebase verification

Digital Asset Links verification needed for getconverse.app domain

The verification shows that:

  • converse.xyz has proper Digital Asset Links configuration with correct package name and SHA-256 fingerprints
  • getconverse.app redirects and doesn't serve the required assetlinks.json file

Since App Links with android:autoVerify="true" requires both domains to have valid Digital Asset Links files, please:

🔗 Analysis chain

Verify domain ownership for App Links

The android:autoVerify="true" requires proper domain ownership verification through Digital Asset Links.

Ensure both domains have proper Digital Asset Links files containing your app's package name and SHA-256 certificate fingerprint.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if Digital Asset Links files are accessible for both domains
echo "Checking Digital Asset Links for production domains..."
curl -s https://getconverse.app/.well-known/assetlinks.json
curl -s https://converse.xyz/.well-known/assetlinks.json

Length of output: 613


6-6: 🛠️ Refactor suggestion

Add launch mode and export configurations to MainActivity

For better deep linking behavior and security, consider adding these attributes to the activity:

-        <activity android:name=".MainActivity">
+        <activity 
+            android:name=".MainActivity"
+            android:launchMode="singleTask"
+            android:exported="true">

This ensures:

  • Proper back stack handling for deep links (singleTask)
  • Explicit export declaration (security best practice)
📝 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.

        <activity 
            android:name=".MainActivity"
            android:launchMode="singleTask"
            android:exported="true">
.github/workflows/build-app-release.yml (1)

51-51: ⚠️ Potential issue

Fix the incorrect script path.

The path scripts/Øbuild/eas.js contains an invalid character 'Ø' which will cause build failures.

-        run: node scripts/Øbuild/eas.js --env production
+        run: node scripts/build/eas.js --env production
📝 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.

        run: node scripts/build/eas.js --env production

@lourou lourou force-pushed the lr/convo-mark-as-read branch from b623389 to e681692 Compare December 7, 2024 06:42
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.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (3)
components/Conversation/V3Conversation.tsx (1)

160-161: Remove console.log statements from production code

The console.log statements are useful for debugging but should be removed or replaced with a proper logging mechanism before deploying to production.

  if (isUnread && !messagesLoading && messages?.ids.length && !hasToggledReadStatus) {
-   console.log("== Mark as read?");
    toggleReadStatus();
    setHasToggledReadStatus(true);
  }
features/conversation-list/hooks/useToggleReadStatus.ts (1)

19-20: Remove console.log statements or use a logging library

The console.log statements can clutter the console in production. Consider removing them or using a logging library that can control log levels.

  console.log("useToggleReadStatus", topic, isUnread);

  return useCallback(() => {
    const newStatus = isUnread ? "read" : "unread";
-   console.log("newStatus:", newStatus);
    const timestamp = new Date().getTime();
    setTopicsData({
      [topic]: {
        status: newStatus,
        timestamp,
      },
    });

Also applies to: 23-23

features/conversation-list/hooks/useMessageIsUnread.ts (1)

22-26: Consider removing deprecated conversation parameter

The conversation prop is marked as deprecated. If it's no longer in use, consider removing it to clean up the code and prevent confusion.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b623389 and e681692.

📒 Files selected for processing (4)
  • components/Conversation/V3Conversation.tsx (2 hunks)
  • features/conversation-list/hooks/useMessageIsUnread.ts (1 hunks)
  • features/conversation-list/hooks/useToggleReadStatus.ts (1 hunks)
  • utils/conversation/showUnreadOnConversation.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • utils/conversation/showUnreadOnConversation.ts
🔇 Additional comments (1)
components/Conversation/V3Conversation.tsx (1)

44-45: New hooks imported correctly

The imports for useConversationIsUnread and useToggleReadStatus are properly added and set up for use in the component.

components/Conversation/V3Conversation.tsx Outdated Show resolved Hide resolved
features/conversation-list/hooks/useMessageIsUnread.ts Outdated Show resolved Hide resolved
Copy link
Contributor

github-actions bot commented Dec 7, 2024

Performance Comparison Report

  • Current: 732660e - 2024-12-07 09:10:25Z
  • Baseline: release/3.0.0 (ac1eeaa) - 2024-12-07 09:09:07Z

Significant Changes To Duration

There are no entries

Meaningless Changes To Duration

Show entries
Name Type Duration Count
Avatar Image 10 runs render 1.1 ms → 1.0 ms (-0.1 ms, -9.1%) 1 → 1
Avatar Image 50 runs render 1.1 ms → 1.0 ms (-0.1 ms, -5.6%) 1 → 1
Empty Avatar 10 runs render 0.5 ms → 0.7 ms (+0.2 ms, +40.0%) 🔴 1 → 1
Empty Avatar 50 runs render 0.7 ms → 0.7 ms (-0.0 ms, -5.7%) 1 → 1
Text Component with color prop - 10 runs render 0.2 ms → 0.1 ms (-0.1 ms, -50.0%) 🟢 1 → 1
Text Component with default props - 10 runs render 0.3 ms → 0.2 ms (-0.1 ms, -33.3%) 🟢 1 → 1
Text Component with translation key - 10 runs render 0.2 ms → 0.2 ms 1 → 1
Text Component with weight and size - 10 runs render 0.2 ms → 0.1 ms (-0.1 ms, -50.0%) 🟢 1 → 1
Show details
Name Type Duration Count
Avatar Image 10 runs render Baseline
Mean: 1.1 ms
Stdev: 0.3 ms (28.7%)
Runs: 1 1 1 1 1 1 1 2 1 1
Warmup runs: 2

Current
Mean: 1.0 ms
Stdev: 0.0 ms (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Warmup runs: 2
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Avatar Image 50 runs render Baseline
Mean: 1.1 ms
Stdev: 0.3 ms (31.5%)
Runs: 1 1 1 1 1 2 0 1 1 1 1 1 2 1 1 1 2 1 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Warmup runs: 1

Current
Mean: 1.0 ms
Stdev: 0.1 ms (13.9%)
Runs: 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 10 runs render Baseline
Mean: 0.5 ms
Stdev: 0.5 ms (105.4%)
Runs: 1 0 0 1 1 1 0 0 0 1
Warmup runs: 3

Current
Mean: 0.7 ms
Stdev: 0.5 ms (69.0%)
Runs: 1 1 0 0 1 1 1 0 1 1
Warmup runs: 3
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 50 runs render Baseline
Mean: 0.7 ms
Stdev: 0.5 ms (66.1%)
Runs: 1 1 1 1 0 1 0 0 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 0 1
Warmup runs: 1

Current
Mean: 0.7 ms
Stdev: 0.5 ms (72.5%)
Runs: 1 1 1 0 1 0 0 0 0 1 1 1 0 0 1 0 1 1 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0 1 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with color prop - 10 runs render Baseline
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 1 0 0 0 1 0 0 0 0 0
Warmup runs: 0

Current
Mean: 0.1 ms
Stdev: 0.3 ms (316.2%)
Runs: 0 0 0 0 0 0 0 1 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with default props - 10 runs render Baseline
Mean: 0.3 ms
Stdev: 0.5 ms (161.0%)
Runs: 0 0 1 0 1 0 0 0 0 1
Warmup runs: 0

Current
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 0 0 1 0 0 1 0 0 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with translation key - 10 runs render Baseline
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 0 0 0 0 0 0 1 0 1
Warmup runs: 0

Current
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 1 0 0 1 0 0 0 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with weight and size - 10 runs render Baseline
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 1 0 0 0 0 0 0 0 1 0
Warmup runs: 1

Current
Mean: 0.1 ms
Stdev: 0.3 ms (316.2%)
Runs: 0 0 0 0 0 1 0 0 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Render Count Changes

There are no entries

Render Issues

There are no entries

Added Scenarios

There are no entries

Removed Scenarios

There are no entries

Generated by 🚫 dangerJS against 8cfa15b

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.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
features/conversation-list/hooks/useMessageIsUnread.ts (3)

29-35: Consider adding error handling for edge cases

While the current implementation handles the basic cases well, consider adding error handling for potential edge cases:

  • Invalid topic format
  • Malformed message data
 // Check if status is unread
+if (!topic || typeof topic !== 'string') {
+  console.warn('Invalid topic format');
+  return false;
+}
 if (topicsData[topic]?.status === "unread") return true;

 // Check if the last message was sent by the current user
+if (!lastMessage.senderAddress) {
+  console.warn('Message missing sender address');
+  return false;
+}
 if (lastMessage.senderAddress === currentInboxId) {
   return false;
 }

36-41: Consider memoizing timestamp normalization

The normalizeTimestamp call could be memoized to avoid unnecessary recalculations on every render.

+const normalizedTimestamp = useMemo(() => 
+  normalizeTimestamp(timestampNs)
+, [timestampNs]);

-const timestamp = normalizeTimestamp(timestampNs);
+const timestamp = normalizedTimestamp;

17-42: Add JSDoc documentation for the hook

Consider adding comprehensive JSDoc documentation to clarify:

  • The purpose of the hook
  • Parameter descriptions
  • Return value semantics
  • Example usage
+/**
+ * Hook to determine if a conversation is unread based on various conditions
+ * @param {Object} props - The hook parameters
+ * @param {string} props.topic - The conversation topic identifier
+ * @param {DecodedMessageWithCodecsType} props.lastMessage - The last message in the conversation
+ * @param {number} props.timestamp - The timestamp to compare against (in nanoseconds)
+ * @returns {boolean} True if the conversation is unread, false otherwise
+ * @example
+ * const isUnread = useConversationIsUnread({
+ *   topic: "chat-123",
+ *   lastMessage: message,
+ *   timestamp: Date.now() * 1_000_000
+ * });
+ */
 export const useConversationIsUnread = ({
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d02db88 and d4ebb1c.

📒 Files selected for processing (6)
  • components/PinnedConversations/PinnedV3DMConversation.tsx (0 hunks)
  • components/PinnedConversations/PinnedV3GroupConversation.tsx (0 hunks)
  • components/V3DMListItem.tsx (0 hunks)
  • components/V3GroupConversationListItem.tsx (0 hunks)
  • features/conversation-list/hooks/useMessageIsUnread.ts (2 hunks)
  • features/conversation-list/hooks/useToggleReadStatus.ts (0 hunks)
💤 Files with no reviewable changes (5)
  • components/PinnedConversations/PinnedV3DMConversation.tsx
  • features/conversation-list/hooks/useToggleReadStatus.ts
  • components/PinnedConversations/PinnedV3GroupConversation.tsx
  • components/V3GroupConversationListItem.tsx
  • components/V3DMListItem.tsx
🔇 Additional comments (3)
features/conversation-list/hooks/useMessageIsUnread.ts (3)

Line range hint 1-15: LGTM! Clean imports and well-defined types

The imports are properly organized and the type definition is appropriately simplified by removing the unused conversation parameter.


26-27: LGTM! Good null check addition

Early return for undefined lastMessage is a good practice to prevent potential runtime errors.


17-42: Verify integration with chat entry point

The hook implementation looks solid, but let's verify its integration with the chat entry point to ensure conversations are properly marked as read.

✅ Verification successful

Let me try a different search strategy to verify the integration.


Let me search for the integration with read status toggling since we found the usage but need to verify the marking as read functionality.


Based on the search results, I can now provide a final response as we've found the crucial integration in V3Conversation.tsx that shows the hook is properly integrated with chat entry points.

Implementation correctly marks conversations as read on entry

The hook is properly integrated with the chat system:

  • The useConversationIsUnread hook is used in conversation list items to detect unread status
  • The V3Conversation component implements auto-marking as read on chat entry through:
    useEffect(() => {
      if (isUnread && !messagesLoading && messages?.ids.length) {
        toggleReadStatus();
      }
    });
  • The useToggleReadStatus hook handles the actual status update in the store
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of this hook in chat entry components
echo "Searching for chat entry components using this hook..."
rg -l "useConversationIsUnread.*entering|entering.*useConversationIsUnread" --type ts --type tsx

# Search for the chat entry point implementation
echo "Searching for chat entry implementation..."
ast-grep --pattern 'const $_ = () => {
  $$$
  useConversationIsUnread
  $$$
}'

Length of output: 422


Script:

#!/bin/bash
# Search for files using the hook
echo "Searching for files importing useConversationIsUnread..."
rg -l "useConversationIsUnread"

# Search for chat entry related components
echo "Searching for chat entry related components..."
rg -l "ChatEntry|EnterChat|ChatView" --type ts

# Look for actual implementation using the hook
echo "Looking for components using the hook..."
rg "useConversationIsUnread" -A 5 -B 5

Length of output: 11683


Script:

#!/bin/bash
# Search for the toggle read status implementation
echo "Searching for toggle read status implementation..."
rg "useToggleReadStatus" -A 10 -B 2

# Search for chat entry/navigation related code
echo "Searching for chat navigation/entry code..."
rg "navigation.*chat|onPress.*chat|navigate.*chat" -A 5 -B 5 components/V3DMListItem.tsx components/V3GroupConversationListItem.tsx components/Conversation/V3Conversation.tsx

Length of output: 12404

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.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
components/V3GroupConversationListItem.tsx (2)

13-13: Remove unused import

The useEffect hook is imported but not used in the component.

-import { RefObject, useCallback, useEffect, useMemo, useRef } from "react";
+import { RefObject, useCallback, useMemo, useRef } from "react";

Line range hint 1-434: Overall implementation looks good with minor improvements needed

The implementation successfully addresses the PR objective of marking conversations as read when entering chat. The code is well-structured and properly integrated with existing hooks. Consider:

  1. Removing the unused useEffect import
  2. Verifying the timing of read status updates during navigation

The rest of the implementation, including the Swipeable component integration and hook usage, is clean and follows best practices.

Consider adding logging or analytics to track any potential race conditions between message prefetching and navigation, which could affect the read status update timing.

components/Conversation/V3Conversation.tsx (2)

210-224: Extract common read status logic

The read status management logic is duplicated between DmContent and GroupContent components.

Consider extracting this logic into a custom hook:

const useConversationReadStatus = (messages: any, topic: any, currentAccount: any) => {
  const isUnread = useConversationIsUnread({
    topic,
    lastMessage: messages?.ids?.length ? messages.byId[messages.ids[0]] : undefined,
    timestamp: messages?.ids?.length ? messages.byId[messages.ids[0]]?.sentNs ?? 0 : 0,
  });

  const toggleReadStatus = useToggleReadStatus({
    topic,
    isUnread,
    currentAccount,
  });

  useMarkAsReadOnEnter({
    messagesLoading: messages?.isLoading,
    isUnread,
    toggleReadStatus,
  });

  return { isUnread, toggleReadStatus };
};

308-326: Clean implementation with minor improvements needed

The hook implementation is solid with proper use of useRef to prevent multiple mark-as-read calls. However, there are a few improvements to consider:

  1. Remove the debug console.log statement
  2. Add error handling for toggleReadStatus call

Consider this cleaner implementation:

  const useMarkAsReadOnEnter = ({
    messagesLoading,
    isUnread,
    toggleReadStatus,
  }: {
    messagesLoading: boolean;
    isUnread: boolean;
    toggleReadStatus: () => void;
  }) => {
    const hasMarkedAsRead = useRef(false);

    useEffect(() => {
      if (isUnread && !messagesLoading && !hasMarkedAsRead.current) {
-       console.log("Mark as read?");
        try {
          toggleReadStatus();
          hasMarkedAsRead.current = true;
        } catch (error) {
          console.error('Failed to mark conversation as read:', error);
        }
      }
    }, [isUnread, messagesLoading, toggleReadStatus]);
  };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d4ebb1c and e5de05a.

📒 Files selected for processing (3)
  • components/Conversation/V3Conversation.tsx (5 hunks)
  • components/V3GroupConversationListItem.tsx (3 hunks)
  • features/conversation-list/hooks/useToggleReadStatus.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • features/conversation-list/hooks/useToggleReadStatus.ts
🔇 Additional comments (4)
components/V3GroupConversationListItem.tsx (2)

373-375: LGTM: Proper ref handling for Swipeable component

The useRef hook is correctly typed and integrated with the Swipeable component.


394-394: Verify read status update timing

The implementation handles navigation and prefetching, but we should verify that the read status is consistently updated when entering the chat.

✅ Verification successful

Based on the search results, I can now generate a final response. The code shows a well-coordinated flow between prefetching, navigation, and read status updates:

Read status updates are properly synchronized

The implementation is safe from race conditions because:

  • prefetchConversationMessages is called before navigation and uses React Query's prefetch mechanism
  • useMarkAsReadOnEnter hook in V3Conversation handles the read status update after entering the conversation
  • Read status updates are managed through a centralized store using setTopicsData with proper timestamps

The read status update timing is properly handled through:

  1. Prefetch initiated before navigation
  2. Read status toggle executed after entering conversation
  3. Atomic store updates with synchronized timestamps
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for read status updates in navigation context
rg -A 5 "prefetchConversationMessages|useConversationIsUnread|useToggleReadStatus" --type ts --type tsx

# Look for potential race conditions in message prefetching
ast-grep --pattern 'prefetchConversationMessages($_)' 

Length of output: 189


Script:

#!/bin/bash
# Search for read status updates and navigation patterns with broader file extensions
rg -A 5 "prefetchConversationMessages|useConversationIsUnread|useToggleReadStatus" --type-add 'tsx:*.{tsx,ts}' --type tsx

# Look for navigation and read status handling patterns
rg -A 5 "markAsRead|setUnread|navigation" --type-add 'tsx:*.{tsx,ts}' --type tsx

# Search for conversation-related hooks and their implementations
rg -A 5 "useConversation|useMessages" --type-add 'tsx:*.{tsx,ts}' --type tsx

Length of output: 88447


Script:

#!/bin/bash
# Search for read status update implementation and hooks
rg -A 10 "useMarkAsReadOnEnter|markAsRead" --type-add 'tsx:*.{tsx,ts}' --type tsx

# Look for conversation message prefetching implementation
rg -A 10 "prefetchConversationMessages" --type-add 'tsx:*.{tsx,ts}' --type tsx

# Search for conversation store updates related to read status
rg -A 5 "setTopicsData|updateReadStatus" --type-add 'tsx:*.{tsx,ts}' --type tsx

Length of output: 12647

components/Conversation/V3Conversation.tsx (2)

44-45: LGTM: Clean import declarations

The new hook imports are properly organized and follow the existing import structure.


153-157: Verify read status behavior across different scenarios

The implementation looks correct, but we should verify the behavior in various scenarios:

  1. New messages arriving while in chat
  2. Multiple rapid chat entries
  3. Network failures during status update

Let's check for any existing test coverage:

Also applies to: 220-224

✅ Verification successful

Based on the gathered information, I can now generate the final response:

Implementation has sufficient error handling and state management

The implementation of useMarkAsReadOnEnter is robust and handles the scenarios well:

  • Uses useRef to prevent multiple mark-as-read calls
  • Only triggers when messages are loaded and conversation is unread
  • toggleReadStatus is wrapped in a store action that handles state updates safely
  • Error handling is managed at the store level through useChatStore

The concerns about various scenarios are addressed:

  1. New messages arriving: State is managed through chat store
  2. Multiple rapid entries: Prevented by hasMarkedAsRead ref
  3. Network failures: Handled at store level with state rollback capability
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for tests related to conversation read status
rg -t ts -t tsx "describe.*mark.*read|test.*mark.*read|it.*mark.*read" --glob "**/*.{spec,test}.{ts,tsx}"

# Check for existing error handling in toggleReadStatus
ast-grep --pattern 'try {
  $$$
  toggleReadStatus($$$)
  $$$
} catch'

Length of output: 208


Script:

#!/bin/bash
# Search for tests with corrected file glob
rg -t typescript -t tsx "describe.*mark.*read|test.*mark.*read|it.*mark.*read" "**/*.{spec,test}.{ts,tsx}"

# Look for error handling around toggleReadStatus calls
rg -A 3 "toggleReadStatus" 

# Check implementation of useMarkAsReadOnEnter hook
fd "useMarkAsReadOnEnter" --exec cat {}

Length of output: 7498


Script:

#!/bin/bash
# Search for useMarkAsReadOnEnter hook implementation
rg -A 10 "useMarkAsReadOnEnter.*=.*{" 

# Look for useToggleReadStatus implementation to understand error handling
rg -A 10 "useToggleReadStatus.*=.*{" 

# Check for any error boundaries or error handling patterns around the conversation component
rg -A 3 "ErrorBoundary|try.*catch" "components/Conversation/**"

Length of output: 441


Script:

#!/bin/bash
# Search for useMarkAsReadOnEnter hook implementation with fixed regex
rg -A 10 "useMarkAsReadOnEnter" 

# Look for useToggleReadStatus implementation with fixed regex
rg -A 10 "const useToggleReadStatus" 

# Check for error handling in conversation components
rg -A 3 "try|catch|Error" "components/"

Length of output: 45629

components/Conversation/V3Conversation.tsx Outdated Show resolved Hide resolved
@lourou lourou marked this pull request as ready for review December 7, 2024 09:05
@lourou lourou requested a review from a team as a code owner December 7, 2024 09:05
technoplato pushed a commit that referenced this pull request Dec 17, 2024
* Remove unused helper method `showUnreadOnConversation`

* WIP read/unread

* Fix

* Remove dependency from conversation prop

* Fix

* Add null check for messages array

* Remove log
This was referenced Jan 8, 2025
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.

Conversation is not marked as read when entering chat
2 participants