Navigation for permalink and Tablet fixes (#9116)
* typescript and view component for permalink with user and message * Old post edited handling in permalink * Added test and update flag value to EnablePermalinkPreview * Added test for permalink_preview component * Added test for content/index.tsx for permalink * Addressed review comments * Unit test for missing file and review comments * Added test to check handlePostEdited permalink sync only calls one time only * Change TouchableOpacity to Pressable * When user not found fetch the user from the server * Removed the redundant test in the test for permalink_preview/index? * ts to tsx * Removed the circular dependency * Address review comments * displayname fallback * remove permalink when permalink post is deleted * UX review comments * Linter fixes * Test fixes * File attachment in permalink preview component * Fix the width and height of the image in permalink * Added gredient when exceeds height of permalink container * Minor * Updated tests * Minor * Review comments * Minor review comments * type fixes * Review comments * Minor * Mention ability in permalink preview * Support for external link in permalink * Handle device not connected update permalink post * test fixes * Address review comments * Minor * Merge fixes * Addressed review comments * Fix content.test.tsx after permalink branch merge - Updated test expectations to use embedData prop instead of post prop - Fixed assertions to match the new PermalinkPreview API - All content tests now pass * review comments * Review comments * Some more review comments * Minor * Fixed the undefined issue for opengraph component metadata * More fixes * Navigation for permalink * Tablet fixes * type chech for site name * linter fixes * UX review and remove show more height not require * Fix tests * Fixed the navigation issue for DM's * Minor fixes due to merge main --------- Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
This commit is contained in:
parent
a5d7bf7db4
commit
4e95364344
3 changed files with 75 additions and 4 deletions
|
|
@ -48,6 +48,9 @@ const styles = StyleSheet.create({
|
||||||
marginTop: {
|
marginTop: {
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
},
|
},
|
||||||
|
rowPermalinkPreview: {
|
||||||
|
marginTop: 0,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Files = ({
|
const Files = ({
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import {fireEvent} from '@testing-library/react-native';
|
import {fireEvent} from '@testing-library/react-native';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import {showPermalink} from '@actions/remote/permalink';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import DatabaseManager from '@database/manager';
|
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 ServerDataOperator from '@database/operator/server_data_operator';
|
||||||
import type {Database} from '@nozbe/watermelondb';
|
import type {Database} from '@nozbe/watermelondb';
|
||||||
|
|
||||||
|
jest.mock('@actions/remote/permalink', () => ({
|
||||||
|
showPermalink: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('@components/markdown', () => ({
|
jest.mock('@components/markdown', () => ({
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
default: jest.fn(),
|
default: jest.fn(),
|
||||||
|
|
@ -29,6 +34,8 @@ describe('components/post_list/post/body/content/permalink_preview/PermalinkPrev
|
||||||
const serverUrl = 'http://localhost:8065';
|
const serverUrl = 'http://localhost:8065';
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
|
||||||
await DatabaseManager.init([serverUrl]);
|
await DatabaseManager.init([serverUrl]);
|
||||||
const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||||
database = serverDatabaseAndOperator.database;
|
database = serverDatabaseAndOperator.database;
|
||||||
|
|
@ -152,6 +159,43 @@ describe('components/post_list/post/body/content/permalink_preview/PermalinkPrev
|
||||||
expect(getByTestId('permalink-preview-container')).toBeTruthy();
|
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', () => {
|
it('should display author name from user model', () => {
|
||||||
const {getByText} = renderPermalinkPreview(baseProps);
|
const {getByText} = renderPermalinkPreview(baseProps);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,18 @@ import {LinearGradient} from 'expo-linear-gradient';
|
||||||
import React, {useMemo, useCallback, useEffect, useState} from 'react';
|
import React, {useMemo, useCallback, useEffect, useState} from 'react';
|
||||||
import {Text, View, Pressable, type LayoutChangeEvent} from 'react-native';
|
import {Text, View, Pressable, type LayoutChangeEvent} from 'react-native';
|
||||||
|
|
||||||
|
import {showPermalink} from '@actions/remote/permalink';
|
||||||
import {fetchUsersByIds} from '@actions/remote/user';
|
import {fetchUsersByIds} from '@actions/remote/user';
|
||||||
import EditedIndicator from '@components/edited_indicator';
|
import EditedIndicator from '@components/edited_indicator';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import FormattedTime from '@components/formatted_time';
|
import FormattedTime from '@components/formatted_time';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import ProfilePicture from '@components/profile_picture';
|
import ProfilePicture from '@components/profile_picture';
|
||||||
|
import {View as ViewConstants} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {useUserLocale} from '@context/user_locale';
|
import {useUserLocale} from '@context/user_locale';
|
||||||
import {useWindowDimensions} from '@hooks/device';
|
import {useIsTablet, useWindowDimensions} from '@hooks/device';
|
||||||
import {usePreventDoubleTap} from '@hooks/utils';
|
import {usePreventDoubleTap} from '@hooks/utils';
|
||||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
@ -33,6 +35,8 @@ import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
const MAX_PERMALINK_PREVIEW_CHARACTERS = 150;
|
const MAX_PERMALINK_PREVIEW_CHARACTERS = 150;
|
||||||
const EDITED_INDICATOR_CONTEXT = ['paragraph'];
|
const EDITED_INDICATOR_CONTEXT = ['paragraph'];
|
||||||
const EMPTY_MENTION_KEYS: UserMentionKey[] = [];
|
const EMPTY_MENTION_KEYS: UserMentionKey[] = [];
|
||||||
|
const MIN_PERMALINK_WIDTH = 340;
|
||||||
|
const TABLET_PADDING_OFFSET = 40;
|
||||||
|
|
||||||
type PermalinkPreviewProps = {
|
type PermalinkPreviewProps = {
|
||||||
embedData: PermalinkEmbedData;
|
embedData: PermalinkEmbedData;
|
||||||
|
|
@ -134,9 +138,21 @@ const PermalinkPreview = ({
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
const locale = useUserLocale();
|
const locale = useUserLocale();
|
||||||
const dimensions = useWindowDimensions();
|
const dimensions = useWindowDimensions();
|
||||||
|
const isTablet = useIsTablet();
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
const [showGradient, setShowGradient] = useState(false);
|
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 maxPermalinkHeight = Math.round(dimensions.height * 0.5);
|
||||||
const textStyles = getMarkdownTextStyles(theme);
|
const textStyles = getMarkdownTextStyles(theme);
|
||||||
const blockStyles = getMarkdownBlockStyles(theme);
|
const blockStyles = getMarkdownBlockStyles(theme);
|
||||||
|
|
@ -192,8 +208,13 @@ const PermalinkPreview = ({
|
||||||
const hasFiles = filesInfo.length > 0;
|
const hasFiles = filesInfo.length > 0;
|
||||||
|
|
||||||
const handlePress = usePreventDoubleTap(useCallback(() => {
|
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 handleContentLayout = useCallback((event: LayoutChangeEvent) => {
|
||||||
const {height} = event.nativeEvent.layout;
|
const {height} = event.nativeEvent.layout;
|
||||||
|
|
@ -208,7 +229,10 @@ const PermalinkPreview = ({
|
||||||
<Pressable
|
<Pressable
|
||||||
style={({pressed}) => [
|
style={({pressed}) => [
|
||||||
styles.container,
|
styles.container,
|
||||||
{opacity: pressed ? 0.8 : 1},
|
{
|
||||||
|
opacity: pressed ? 0.8 : 1,
|
||||||
|
maxWidth,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
onPress={handlePress}
|
onPress={handlePress}
|
||||||
testID='permalink-preview-container'
|
testID='permalink-preview-container'
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue