From 265c4fe8a6c957a099100a7a40888aa5a14e8467 Mon Sep 17 00:00:00 2001 From: Tanmay Vardhaman Thole <72058456+tanmaythole@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:58:03 +0530 Subject: [PATCH] [MM-42565] Toast - Follow/Unfollow thread with undo functionality (#7267) --- app/actions/remote/thread.ts | 8 +++++++- .../follow_thread_option/follow_thread_option.tsx | 2 +- app/components/post_list/post/footer/footer.tsx | 2 +- app/components/toast/index.tsx | 3 +-- app/constants/snack_bar.ts | 14 ++++++++++++++ .../thread_follow_button/thread_follow_button.tsx | 2 +- app/utils/snack_bar/index.ts | 7 +++++++ 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/actions/remote/thread.ts b/app/actions/remote/thread.ts index ca3dfb6e3..b9edb9d9b 100644 --- a/app/actions/remote/thread.ts +++ b/app/actions/remote/thread.ts @@ -12,6 +12,7 @@ import {getPostById} from '@queries/servers/post'; import {getConfigValue, getCurrentChannelId, getCurrentTeamId} from '@queries/servers/system'; import {getIsCRTEnabled, getThreadById, getTeamThreadsSyncData} from '@queries/servers/thread'; import {getCurrentUser} from '@queries/servers/user'; +import {showThreadFollowingSnackbar} from '@utils/snack_bar'; import {getThreadsListEdges} from '@utils/thread'; import {forceLogoutIfNecessary} from './session'; @@ -202,7 +203,7 @@ export const markThreadAsUnread = async (serverUrl: string, teamId: string, thre } }; -export const updateThreadFollowing = async (serverUrl: string, teamId: string, threadId: string, state: boolean) => { +export const updateThreadFollowing = async (serverUrl: string, teamId: string, threadId: string, state: boolean, showSnackBar: boolean) => { const database = DatabaseManager.serverDatabases[serverUrl]?.database; if (!database) { @@ -228,6 +229,11 @@ export const updateThreadFollowing = async (serverUrl: string, teamId: string, t // Update locally await updateThread(serverUrl, threadId, {is_following: state}); + if (showSnackBar) { + const onUndo = () => updateThreadFollowing(serverUrl, teamId, threadId, !state, false); + showThreadFollowingSnackbar(state, onUndo); + } + return {data}; } catch (error) { forceLogoutIfNecessary(serverUrl, error as ClientErrorProps); diff --git a/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx b/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx index 475e55ea9..6c07b742e 100644 --- a/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx +++ b/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx @@ -50,7 +50,7 @@ const FollowThreadOption = ({bottomSheetId, thread, teamId}: FollowThreadOptionP return; } await dismissBottomSheet(bottomSheetId); - updateThreadFollowing(serverUrl, teamId, thread.id, !thread.isFollowing); + updateThreadFollowing(serverUrl, teamId, thread.id, !thread.isFollowing, true); }, [bottomSheetId, teamId, thread]); const followThreadOptionTestId = thread.isFollowing ? 'post_options.following_thread.option' : 'post_options.follow_thread.option'; diff --git a/app/components/post_list/post/footer/footer.tsx b/app/components/post_list/post/footer/footer.tsx index d8477f572..1d017cf7c 100644 --- a/app/components/post_list/post/footer/footer.tsx +++ b/app/components/post_list/post/footer/footer.tsx @@ -86,7 +86,7 @@ const Footer = ({channelId, location, participants, teamId, thread}: Props) => { if (teamId == null) { return; } - updateThreadFollowing(serverUrl, teamId, thread.id, !thread.isFollowing); + updateThreadFollowing(serverUrl, teamId, thread.id, !thread.isFollowing, true); }), [thread.isFollowing]); let repliesComponent; diff --git a/app/components/toast/index.tsx b/app/components/toast/index.tsx index a05968b4f..eb35597a5 100644 --- a/app/components/toast/index.tsx +++ b/app/components/toast/index.tsx @@ -39,8 +39,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ flex: 1, flexDirection: 'row', height: TOAST_HEIGHT, - paddingLeft: 20, - paddingRight: 10, + paddingHorizontal: 16, shadowColor: changeOpacity('#000', 0.12), shadowOffset: {width: 0, height: 4}, shadowRadius: 6, diff --git a/app/constants/snack_bar.ts b/app/constants/snack_bar.ts index 886ba7a0a..8d1fccda6 100644 --- a/app/constants/snack_bar.ts +++ b/app/constants/snack_bar.ts @@ -7,12 +7,14 @@ import keyMirror from '@utils/key_mirror'; export const SNACK_BAR_TYPE = keyMirror({ ADD_CHANNEL_MEMBERS: null, FAVORITE_CHANNEL: null, + FOLLOW_THREAD: null, LINK_COPIED: null, MESSAGE_COPIED: null, MUTE_CHANNEL: null, REMOVE_CHANNEL_USER: null, UNFAVORITE_CHANNEL: null, UNMUTE_CHANNEL: null, + UNFOLLOW_THREAD: null, }); type SnackBarConfig = { @@ -35,6 +37,12 @@ export const SNACK_BAR_CONFIG: Record = { iconName: 'star', canUndo: true, }, + FOLLOW_THREAD: { + id: t('snack.bar.following.thread'), + defaultMessage: 'Thread followed', + iconName: 'check', + canUndo: true, + }, LINK_COPIED: { id: t('snack.bar.link.copied'), defaultMessage: 'Link copied to clipboard', @@ -71,6 +79,12 @@ export const SNACK_BAR_CONFIG: Record = { iconName: 'bell-outline', canUndo: true, }, + UNFOLLOW_THREAD: { + id: t('snack.bar.unfollow.thread'), + defaultMessage: 'Thread unfollowed', + iconName: 'check', + canUndo: true, + }, }; export default { diff --git a/app/screens/thread/thread_follow_button/thread_follow_button.tsx b/app/screens/thread/thread_follow_button/thread_follow_button.tsx index 276836c8b..118bf1cee 100644 --- a/app/screens/thread/thread_follow_button/thread_follow_button.tsx +++ b/app/screens/thread/thread_follow_button/thread_follow_button.tsx @@ -56,7 +56,7 @@ function ThreadFollow({isFollowing, teamId, threadId}: Props) { const serverUrl = useServerUrl(); const onPress = preventDoubleTap(() => { - updateThreadFollowing(serverUrl, teamId, threadId, !isFollowing); + updateThreadFollowing(serverUrl, teamId, threadId, !isFollowing, false); }); const containerStyle: StyleProp = [styles.container]; diff --git a/app/utils/snack_bar/index.ts b/app/utils/snack_bar/index.ts index c623bab25..d32bfb94c 100644 --- a/app/utils/snack_bar/index.ts +++ b/app/utils/snack_bar/index.ts @@ -47,3 +47,10 @@ export const showRemoveChannelUserSnackbar = () => { sourceScreen: Screens.MANAGE_CHANNEL_MEMBERS, }); }; + +export const showThreadFollowingSnackbar = (following: boolean, onAction: () => void) => { + return showSnackBar({ + onAction, + barType: following ? SNACK_BAR_TYPE.FOLLOW_THREAD : SNACK_BAR_TYPE.UNFOLLOW_THREAD, + }); +};