diff --git a/app/components/files/files.tsx b/app/components/files/files.tsx index 508c1ee54..336fc6211 100644 --- a/app/components/files/files.tsx +++ b/app/components/files/files.tsx @@ -48,6 +48,9 @@ const styles = StyleSheet.create({ marginTop: { marginTop: 10, }, + rowPermalinkPreview: { + marginTop: 0, + }, }); const Files = ({ diff --git a/app/components/post_list/post/body/content/permalink_preview/permalink_preview.test.tsx b/app/components/post_list/post/body/content/permalink_preview/permalink_preview.test.tsx index 430c4967b..67256df80 100644 --- a/app/components/post_list/post/body/content/permalink_preview/permalink_preview.test.tsx +++ b/app/components/post_list/post/body/content/permalink_preview/permalink_preview.test.tsx @@ -4,6 +4,7 @@ import {fireEvent} from '@testing-library/react-native'; import React from 'react'; +import {showPermalink} from '@actions/remote/permalink'; import Markdown from '@components/markdown'; import {Screens} from '@constants'; import DatabaseManager from '@database/manager'; @@ -15,6 +16,10 @@ import PermalinkPreview from './permalink_preview'; import type ServerDataOperator from '@database/operator/server_data_operator'; import type {Database} from '@nozbe/watermelondb'; +jest.mock('@actions/remote/permalink', () => ({ + showPermalink: jest.fn(), +})); + jest.mock('@components/markdown', () => ({ __esModule: true, default: jest.fn(), @@ -29,6 +34,8 @@ describe('components/post_list/post/body/content/permalink_preview/PermalinkPrev const serverUrl = 'http://localhost:8065'; beforeEach(async () => { + jest.clearAllMocks(); + await DatabaseManager.init([serverUrl]); const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl); database = serverDatabaseAndOperator.database; @@ -152,6 +159,43 @@ describe('components/post_list/post/body/content/permalink_preview/PermalinkPrev expect(getByTestId('permalink-preview-container')).toBeTruthy(); }); + it('should call showPermalink with correct parameters when container is pressed', () => { + const mockShowPermalink = jest.mocked(showPermalink); + const {getByTestId} = renderPermalinkPreview(baseProps); + const permalinkContainer = getByTestId('permalink-preview-container'); + + fireEvent.press(permalinkContainer); + + expect(mockShowPermalink).toHaveBeenCalledWith( + serverUrl, + baseProps.embedData.team_name, + baseProps.embedData.post_id, + ); + }); + + it('should call showPermalink even when team_name is empty for DM posts', () => { + const mockShowPermalink = jest.mocked(showPermalink); + const dmProps = { + ...baseProps, + embedData: { + ...baseProps.embedData, + team_name: '', + channel_type: 'D', + channel_display_name: 'testuser', + }, + }; + const {getByTestId} = renderPermalinkPreview(dmProps); + const permalinkContainer = getByTestId('permalink-preview-container'); + + fireEvent.press(permalinkContainer); + + expect(mockShowPermalink).toHaveBeenCalledWith( + serverUrl, + '', + baseProps.embedData.post_id, + ); + }); + it('should display author name from user model', () => { const {getByText} = renderPermalinkPreview(baseProps); diff --git a/app/components/post_list/post/body/content/permalink_preview/permalink_preview.tsx b/app/components/post_list/post/body/content/permalink_preview/permalink_preview.tsx index 9d7e01ce4..586dc7c28 100644 --- a/app/components/post_list/post/body/content/permalink_preview/permalink_preview.tsx +++ b/app/components/post_list/post/body/content/permalink_preview/permalink_preview.tsx @@ -5,16 +5,18 @@ import {LinearGradient} from 'expo-linear-gradient'; import React, {useMemo, useCallback, useEffect, useState} from 'react'; import {Text, View, Pressable, type LayoutChangeEvent} from 'react-native'; +import {showPermalink} from '@actions/remote/permalink'; import {fetchUsersByIds} from '@actions/remote/user'; import EditedIndicator from '@components/edited_indicator'; import FormattedText from '@components/formatted_text'; import FormattedTime from '@components/formatted_time'; import Markdown from '@components/markdown'; import ProfilePicture from '@components/profile_picture'; +import {View as ViewConstants} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {useUserLocale} from '@context/user_locale'; -import {useWindowDimensions} from '@hooks/device'; +import {useIsTablet, useWindowDimensions} from '@hooks/device'; import {usePreventDoubleTap} from '@hooks/utils'; import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -33,6 +35,8 @@ import type {AvailableScreens} from '@typings/screens/navigation'; const MAX_PERMALINK_PREVIEW_CHARACTERS = 150; const EDITED_INDICATOR_CONTEXT = ['paragraph']; const EMPTY_MENTION_KEYS: UserMentionKey[] = []; +const MIN_PERMALINK_WIDTH = 340; +const TABLET_PADDING_OFFSET = 40; type PermalinkPreviewProps = { embedData: PermalinkEmbedData; @@ -134,9 +138,21 @@ const PermalinkPreview = ({ const serverUrl = useServerUrl(); const locale = useUserLocale(); const dimensions = useWindowDimensions(); + const isTablet = useIsTablet(); const styles = getStyleSheet(theme); const [showGradient, setShowGradient] = useState(false); + const maxWidth = useMemo(() => { + if (!isTablet) { + return undefined; + } + + const deviceSize = Math.min(dimensions.width, dimensions.height); + const availableWidth = deviceSize - ViewConstants.TABLET_SIDEBAR_WIDTH; + + return Math.max(availableWidth - TABLET_PADDING_OFFSET, MIN_PERMALINK_WIDTH); + }, [dimensions.width, dimensions.height, isTablet]); + const maxPermalinkHeight = Math.round(dimensions.height * 0.5); const textStyles = getMarkdownTextStyles(theme); const blockStyles = getMarkdownBlockStyles(theme); @@ -192,8 +208,13 @@ const PermalinkPreview = ({ const hasFiles = filesInfo.length > 0; const handlePress = usePreventDoubleTap(useCallback(() => { - // Navigation will be implemented in Task 5 - }, [])); + const teamName = embedData.team_name; + const postId = embedData.post_id; + + if (postId) { + showPermalink(serverUrl, teamName, postId); + } + }, [embedData.team_name, embedData.post_id, serverUrl])); const handleContentLayout = useCallback((event: LayoutChangeEvent) => { const {height} = event.nativeEvent.layout; @@ -208,7 +229,10 @@ const PermalinkPreview = ({ [ styles.container, - {opacity: pressed ? 0.8 : 1}, + { + opacity: pressed ? 0.8 : 1, + maxWidth, + }, ]} onPress={handlePress} testID='permalink-preview-container'