diff --git a/.jscodeshift/toast-v2.js b/.jscodeshift/toast-v2.js new file mode 100644 --- /dev/null +++ b/.jscodeshift/toast-v2.js @@ -0,0 +1,106 @@ +/** + * Codemod to replace namespaced React calls with named imports + * + * Before: + * import * as Toast from '#/view/com/util/Toast' + * Toast.show(message, 'xmark') + * + * After: + * import * as Toast from '#/components/Toast' + * Toast.show(message, {type: 'error'}) + * + * Usage: jscodeshift -t .jscodeshift/toast-v2.js + * Example: jscodeshift -t .jscodeshift/toast-v2.js src/App.native.tsx + */ + +/* eslint-disable */ + +export const parser = 'tsx' + +const OLD_IMPORT = '#/view/com/util/Toast' +const NEW_IMPORT = '#/components/Toast' + +const convertLegacyToastType = type => { + switch (type) { + // these ones are fine + case 'default': + case 'success': + case 'error': + case 'warning': + case 'info': + return type + // legacy ones need conversion + case 'xmark': + return 'error' + case 'exclamation-circle': + return 'warning' + case 'check': + return 'success' + case 'clipboard-check': + return 'success' + case 'circle-exclamation': + case 'exclamation-circle': + return 'warning' + default: + return 'default' + } +} + +export default function transformer(file, api) { + const j = api.jscodeshift + const root = j(file.source) + + // Find Toast import declarations using the old path + const toastImports = root + .find(j.ImportDeclaration) + .filter(path => path.value.source.value === OLD_IMPORT) + + if (toastImports.length === 0) { + return file.source + } + + // Update import path + toastImports.forEach(path => { + path.value.source.value = NEW_IMPORT + }) + + // Collect all local names the Toast namespace is bound to + const toastLocalNames = new Set() + toastImports.forEach(path => { + path.value.specifiers.forEach(spec => { + if (spec.type === 'ImportNamespaceSpecifier') { + toastLocalNames.add(spec.local.name) + } + }) + }) + + // Transform Toast.show(message, type) calls + root.find(j.CallExpression).forEach(path => { + const {callee, arguments: args} = path.value + + // Match .show(...) + if ( + callee.type !== 'MemberExpression' || + callee.object.type !== 'Identifier' || + !toastLocalNames.has(callee.object.name) || + callee.property.name !== 'show' + ) { + return + } + + // Only transform 2-arg calls where the second arg is a string literal + if (args.length !== 2) return + const typeArg = args[1] + if (typeArg.type !== 'StringLiteral' && typeArg.type !== 'Literal') return + + const legacyType = typeArg.value + const newType = convertLegacyToastType(legacyType) + + // Replace the second argument with an options object: {type: 'newType'} + args[1] = j.objectExpression([ + j.property('init', j.identifier('type'), j.stringLiteral(newType)), + ]) + }) + + return root.toSource() +} diff --git a/src/App.native.tsx b/src/App.native.tsx --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -58,7 +58,6 @@ import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' import {TestCtrls} from '#/view/com/testing/TestCtrls' -import * as Toast from '#/view/com/util/Toast' import {Shell} from '#/view/shell' import {ThemeProvider as Alf} from '#/alf' import {useColorModeTheme} from '#/alf/util/useColorModeTheme' @@ -68,6 +67,7 @@ import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' import {Provider as PortalProvider} from '#/components/Portal' import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' +import * as Toast from '#/components/Toast' import {ToastOutlet} from '#/components/Toast' import { prefetchAgeAssuranceConfig, @@ -139,10 +139,9 @@ }, [resumeSession]) useEffect(() => { return listenSessionDropped(() => { - Toast.show( - _(msg`Sorry! Your session expired. Please sign in again.`), - 'info', - ) + Toast.show(_(msg`Sorry! Your session expired. Please sign in again.`), { + type: 'info', + }) }) }, [_]) diff --git a/src/App.web.tsx b/src/App.web.tsx --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -47,7 +47,6 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide' import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' -import * as Toast from '#/view/com/util/Toast' import {Shell} from '#/view/shell/index' import {ThemeProvider as Alf} from '#/alf' import {useColorModeTheme} from '#/alf/util/useColorModeTheme' @@ -58,6 +57,7 @@ import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' import {Provider as PortalProvider} from '#/components/Portal' import {Provider as ActiveVideoProvider} from '#/components/Post/Embed/VideoEmbed/ActiveVideoWebContext' import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' +import * as Toast from '#/components/Toast' import {ToastOutlet} from '#/components/Toast' import { prefetchAgeAssuranceConfig, @@ -115,10 +115,9 @@ }, [resumeSession]) useEffect(() => { return listenSessionDropped(() => { - Toast.show( - _(msg`Sorry! Your session expired. Please sign in again.`), - 'info', - ) + Toast.show(_(msg`Sorry! Your session expired. Please sign in again.`), { + type: 'info', + }) }) }, [_]) diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx --- a/src/components/FeedCard.tsx +++ b/src/components/FeedCard.tsx @@ -18,7 +18,6 @@ usePreferencesQuery, useRemoveFeedMutation, } from '#/state/queries/preferences' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, select, useTheme} from '#/alf' import { @@ -33,6 +32,7 @@ import {Link as InternalLink, type LinkProps} from '#/components/Link' import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' import {RichText, type RichTextProps} from '#/components/RichText' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useActiveLiveEventFeedUris} from '#/features/liveEvents/context' import type * as bsky from '#/types/bsky' @@ -313,7 +313,9 @@ } Toast.show(l({message: 'Feeds updated!', context: 'toast'})) } catch (err: any) { logger.error(err, {message: `FeedCard: failed to update feeds`, pin}) - Toast.show(l`Failed to update feeds`, 'xmark') + Toast.show(l`Failed to update feeds`, { + type: 'error', + }) } }, [l, pin, saveFeeds, removeFeed, uri, savedFeedConfig, type], diff --git a/src/components/PostControls/PostMenu/PostMenuItems.tsx b/src/components/PostControls/PostMenu/PostMenuItems.tsx --- a/src/components/PostControls/PostMenu/PostMenuItems.tsx +++ b/src/components/PostControls/PostMenu/PostMenuItems.tsx @@ -56,7 +56,6 @@ useToggleReplyVisibilityMutation, } from '#/state/queries/threadgate' import {useRequireAuth, useSession} from '#/state/session' import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' -import * as Toast from '#/view/com/util/Toast' import {useDialogControl} from '#/components/Dialog' import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' import { @@ -93,6 +92,7 @@ ReportDialog, useReportDialogControl, } from '#/components/moderation/ReportDialog' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {IS_INTERNAL} from '#/env' import * as bsky from '#/types/bsky' @@ -216,7 +216,9 @@ } }, e => { logger.error('Failed to delete post', {message: e}) - Toast.show(l`Failed to delete post, please try again`, 'xmark') + Toast.show(l`Failed to delete post, please try again`, { + type: 'error', + }) }, ) } @@ -246,7 +248,9 @@ } catch (err) { const e = err as Error if (e?.name !== 'AbortError') { logger.error('Failed to toggle thread mute', {message: e}) - Toast.show(l`Failed to toggle thread mute, please try again`, 'xmark') + Toast.show(l`Failed to toggle thread mute, please try again`, { + type: 'error', + }) } } } @@ -265,7 +269,9 @@ const onCopyPostText = () => { const str = richTextToString(richText, true) void Clipboard.setStringAsync(str) - Toast.show(l`Copied to clipboard`, 'clipboard-check') + Toast.show(l`Copied to clipboard`, { + type: 'success', + }) } const onPressTranslate = () => { @@ -434,7 +440,9 @@ } catch (err) { const e = err as Error if (e?.name !== 'AbortError') { logger.error('Failed to block account', {message: e}) - Toast.show(l`There was an issue! ${e.toString()}`, 'xmark') + Toast.show(l`There was an issue! ${e.toString()}`, { + type: 'error', + }) } } finally { ax.metric('postMenu:blockAccount', { @@ -455,7 +463,9 @@ } catch (err) { const e = err as Error if (e?.name !== 'AbortError') { logger.error('Failed to unmute account', {message: e}) - Toast.show(l`There was an issue! ${e.toString()}`, 'xmark') + Toast.show(l`There was an issue! ${e.toString()}`, { + type: 'error', + }) } } finally { ax.metric('postMenu:unmuteAccount', { @@ -473,7 +483,9 @@ } catch (err) { const e = err as Error if (e?.name !== 'AbortError') { logger.error('Failed to mute account', {message: e}) - Toast.show(l`There was an issue! ${e.toString()}`, 'xmark') + Toast.show(l`There was an issue! ${e.toString()}`, { + type: 'error', + }) } } finally { ax.metric('postMenu:muteAccount', { diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx --- a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx +++ b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx @@ -12,7 +12,6 @@ import {shareText, shareUrl} from '#/lib/sharing' import {toShareUrl} from '#/lib/strings/url-helpers' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a} from '#/alf' import {Admonition} from '#/components/Admonition' import {useDialogControl} from '#/components/Dialog' @@ -22,6 +21,7 @@ import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane' import * as Menu from '#/components/Menu' +import * as Toast from '#/components/Toast' import {useAgeAssurance} from '#/ageAssurance' import {useAnalytics} from '#/analytics' import {IS_IOS} from '#/env' @@ -71,7 +71,9 @@ await ExpoClipboard.setUrlAsync(url) } else { await ExpoClipboard.setStringAsync(url) } - Toast.show(_(msg`Copied to clipboard`), 'clipboard-check') + Toast.show(_(msg`Copied to clipboard`), { + type: 'success', + }) onShareProp() } diff --git a/src/components/PostControls/index.tsx b/src/components/PostControls/index.tsx --- a/src/components/PostControls/index.tsx +++ b/src/components/PostControls/index.tsx @@ -24,11 +24,11 @@ import { ProgressGuideAction, useProgressGuideControls, } from '#/state/shell/progress-guide' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints} from '#/alf' import {Reply as Bubble} from '#/components/icons/Reply' import {useFormatPostStatCount} from '#/components/PostControls/util' import * as Skele from '#/components/Skeleton' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {BookmarkButton} from './BookmarkButton' import { @@ -106,7 +106,9 @@ const [hasLikeIconBeenToggled, setHasLikeIconBeenToggled] = useState(false) const onPressToggleLike = async () => { if (isBlocked) { - Toast.show(l`Cannot interact with a blocked user`, 'exclamation-circle') + Toast.show(l`Cannot interact with a blocked user`, { + type: 'warning', + }) return } @@ -135,7 +137,9 @@ } const onRepost = async () => { if (isBlocked) { - Toast.show(l`Cannot interact with a blocked user`, 'exclamation-circle') + Toast.show(l`Cannot interact with a blocked user`, { + type: 'warning', + }) return } @@ -161,7 +165,9 @@ } const onQuote = () => { if (isBlocked) { - Toast.show(l`Cannot interact with a blocked user`, 'exclamation-circle') + Toast.show(l`Cannot interact with a blocked user`, { + type: 'warning', + }) return } diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -22,7 +22,6 @@ import {sanitizeHandle} from '#/lib/strings/handles' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {PreviewableUserAvatar, UserAvatar} from '#/view/com/util/UserAvatar' import { atoms as a, @@ -43,6 +42,7 @@ import {Link as InternalLink, type LinkProps} from '#/components/Link' import * as Pills from '#/components/Pills' import {ProfileBadges} from '#/components/ProfileBadges' import {RichText} from '#/components/RichText' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {type Metrics} from '#/analytics' import {useActorStatus} from '#/features/liveNow' @@ -504,7 +504,9 @@ onFollow?.() } catch (e) { const err = e as Error if (err?.name !== 'AbortError') { - Toast.show(l`An issue occurred, please try again.`, 'xmark') + Toast.show(l`An issue occurred, please try again.`, { + type: 'error', + }) } } } @@ -524,7 +526,9 @@ onPressProp?.(e) } catch (e) { const err = e as Error if (err?.name !== 'AbortError') { - Toast.show(l`An issue occurred, please try again.`, 'xmark') + Toast.show(l`An issue occurred, please try again.`, { + type: 'error', + }) } } } diff --git a/src/components/activity-notifications/SubscribeProfileDialog.tsx b/src/components/activity-notifications/SubscribeProfileDialog.tsx --- a/src/components/activity-notifications/SubscribeProfileDialog.tsx +++ b/src/components/activity-notifications/SubscribeProfileDialog.tsx @@ -21,7 +21,6 @@ import {sanitizeHandle} from '#/lib/strings/handles' import {updateProfileShadow} from '#/state/cache/profile-shadow' import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions' import {useAgent} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, platform, useTheme, web} from '#/alf' import {Admonition} from '#/components/Admonition' import { @@ -34,6 +33,7 @@ import * as Dialog from '#/components/Dialog' import * as Toggle from '#/components/forms/Toggle' import {Loader} from '#/components/Loader' import * as ProfileCard from '#/components/ProfileCard' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_WEB} from '#/env' @@ -139,7 +139,9 @@ Toast.show( _( msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`, ), - 'check', + { + type: 'success', + }, ) // filter out the subscription @@ -169,10 +171,14 @@ Toast.show( _( msg`You'll start receiving notifications for ${sanitizeHandle(profile.handle, '@')}!`, ), - 'check', + { + type: 'success', + }, ) } else { - Toast.show(_(msg`Changes saved`), 'check') + Toast.show(_(msg`Changes saved`), { + type: 'success', + }) } } }) diff --git a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx --- a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx +++ b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx @@ -8,12 +8,12 @@ import {useMutation} from '@tanstack/react-query' import {BLUESKY_MOD_SERVICE_HEADERS} from '#/lib/constants' import {useAgent, useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, web} from '#/alf' import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {logger} from '#/ageAssurance' import {useAnalytics} from '#/analytics' @@ -70,7 +70,9 @@ onError: err => { logger.error('AgeAssuranceAppealDialog failed', {safeMessage: err}) Toast.show( _(msg`Age assurance inquiry failed to send, please try again.`), - 'xmark', + { + type: 'error', + }, ) }, onSuccess: () => { diff --git a/src/components/dialogs/PostInteractionSettingsDialog.tsx b/src/components/dialogs/PostInteractionSettingsDialog.tsx --- a/src/components/dialogs/PostInteractionSettingsDialog.tsx +++ b/src/components/dialogs/PostInteractionSettingsDialog.tsx @@ -37,7 +37,6 @@ PostThreadContextProvider, usePostThreadContext, } from '#/state/queries/usePostThread' import {useAgent, useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme, web} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -50,6 +49,7 @@ } from '#/components/icons/Chevron' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {CloseQuote_Stroke2_Corner1_Rounded as QuoteIcon} from '#/components/icons/Quote' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_IOS} from '#/env' @@ -240,7 +240,9 @@ Toast.show( _( msg`There was an issue. Please check your internet connection and try again.`, ), - 'xmark', + { + type: 'error', + }, ) } finally { setIsSaving(false) diff --git a/src/components/dialogs/lists/CreateOrEditListDialog.tsx b/src/components/dialogs/lists/CreateOrEditListDialog.tsx --- a/src/components/dialogs/lists/CreateOrEditListDialog.tsx +++ b/src/components/dialogs/lists/CreateOrEditListDialog.tsx @@ -17,7 +17,6 @@ useListMetadataMutation, } from '#/state/queries/list' import {useAgent} from '#/state/session' import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' -import * as Toast from '#/view/com/util/Toast' import {EditableUserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme, web} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -25,6 +24,7 @@ import * as Dialog from '#/components/Dialog' import * as TextField from '#/components/forms/TextField' import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_WEB} from '#/env' diff --git a/src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx b/src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx --- a/src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx +++ b/src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx @@ -14,7 +14,6 @@ useDangerousListMembershipsQuery, useListMembershipAddMutation, useListMembershipRemoveMutation, } from '#/state/queries/list-memberships' -import * as Toast from '#/view/com/util/Toast' import {atoms as a} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' @@ -24,6 +23,7 @@ SearchablePeopleList, } from '#/components/dialogs/SearchablePeopleList' import {Loader} from '#/components/Loader' import * as ProfileCard from '#/components/ProfileCard' +import * as Toast from '#/components/Toast' import type * as bsky from '#/types/bsky' export function ListAddRemoveUsersDialog({ @@ -113,7 +113,10 @@ onSuccess: () => { Toast.show(_(msg`Added to list`)) onChange?.('add', profile) }, - onError: e => Toast.show(cleanError(e), 'xmark'), + onError: e => + Toast.show(cleanError(e), { + type: 'error', + }), }) const {mutate: listMembershipRemove, isPending: isRemovingPending} = useListMembershipRemoveMutation({ @@ -121,7 +124,10 @@ onSuccess: () => { Toast.show(_(msg`Removed from list`)) onChange?.('remove', profile) }, - onError: e => Toast.show(cleanError(e), 'xmark'), + onError: e => + Toast.show(cleanError(e), { + type: 'error', + }), }) const isMutating = isAddingPending || isRemovingPending diff --git a/src/components/dms/ActionsWrapper.web.tsx b/src/components/dms/ActionsWrapper.web.tsx --- a/src/components/dms/ActionsWrapper.web.tsx +++ b/src/components/dms/ActionsWrapper.web.tsx @@ -6,11 +6,11 @@ import {useLingui} from '@lingui/react' import {useConvoActive} from '#/state/messages/convo' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useTheme} from '#/alf' import {MessageContextMenu} from '#/components/dms/MessageContextMenu' import {DotGrid3x1_Stroke2_Corner0_Rounded as DotsHorizontalIcon} from '#/components/icons/DotGrid' import {EmojiSmile_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji' +import * as Toast from '#/components/Toast' import {EmojiReactionPicker} from './EmojiReactionPicker' import {hasReachedReactionLimit} from './util' @@ -60,11 +60,11 @@ .removeReaction(message.id, emoji) .catch(() => Toast.show(_(msg`Failed to remove emoji reaction`))) } else { if (hasReachedReactionLimit(message, currentAccount?.did)) return - convo - .addReaction(message.id, emoji) - .catch(() => - Toast.show(_(msg`Failed to add emoji reaction`), 'xmark'), - ) + convo.addReaction(message.id, emoji).catch(() => + Toast.show(_(msg`Failed to add emoji reaction`), { + type: 'error', + }), + ) } }, [_, convo, message, currentAccount?.did], diff --git a/src/components/dms/AfterReportDialog.tsx b/src/components/dms/AfterReportDialog.tsx --- a/src/components/dms/AfterReportDialog.tsx +++ b/src/components/dms/AfterReportDialog.tsx @@ -13,12 +13,12 @@ import { useProfileBlockMutationQueue, useProfileQuery, } from '#/state/queries/profile' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf' import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import * as Toggle from '#/components/forms/Toggle' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_NATIVE} from '#/env' @@ -135,7 +135,9 @@ ) } }, onError: () => { - Toast.show(_(msg`Could not leave chat`), 'xmark') + Toast.show(_(msg`Could not leave chat`), { + type: 'error', + }) }, }) @@ -161,7 +163,9 @@ if (actions.includes('leave')) { leaveConvo() } if (toastMsg) { - Toast.show(toastMsg, 'check') + Toast.show(toastMsg, { + type: 'success', + }) } }) } diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx --- a/src/components/dms/ConvoMenu.tsx +++ b/src/components/dms/ConvoMenu.tsx @@ -18,7 +18,6 @@ import { unstableCacheProfileView, useProfileBlockMutationQueue, } from '#/state/queries/profile' -import * as Toast from '#/view/com/util/Toast' import {type ViewStyleProp} from '#/alf' import {atoms as a} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' @@ -40,6 +39,7 @@ import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' import * as Menu from '#/components/Menu' import {ReportDialog} from '#/components/moderation/ReportDialog' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import type * as bsky from '#/types/bsky' let ConvoMenu = ({ @@ -205,7 +205,9 @@ Toast.show(_(msg({message: 'Chat unmuted', context: 'toast'}))) } }, onError: () => { - Toast.show(_(msg`Could not mute chat`), 'xmark') + Toast.show(_(msg`Could not mute chat`), { + type: 'error', + }) }, }) diff --git a/src/components/dms/LeaveConvoPrompt.tsx b/src/components/dms/LeaveConvoPrompt.tsx --- a/src/components/dms/LeaveConvoPrompt.tsx +++ b/src/components/dms/LeaveConvoPrompt.tsx @@ -4,9 +4,9 @@ import {StackActions, useNavigation} from '@react-navigation/native' import {type NavigationProp} from '#/lib/routes/types' import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' -import * as Toast from '#/view/com/util/Toast' import {type DialogOuterProps} from '#/components/Dialog' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {IS_NATIVE} from '#/env' export function LeaveConvoPrompt({ @@ -32,7 +32,9 @@ ) } }, onError: () => { - Toast.show(_(msg`Could not leave chat`), 'xmark') + Toast.show(_(msg`Could not leave chat`), { + type: 'error', + }) }, }) diff --git a/src/components/dms/MessageContextMenu.tsx b/src/components/dms/MessageContextMenu.tsx --- a/src/components/dms/MessageContextMenu.tsx +++ b/src/components/dms/MessageContextMenu.tsx @@ -12,7 +12,6 @@ import {useConvoActive} from '#/state/messages/convo' import {useLanguagePrefs} from '#/state/preferences' import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import * as ContextMenu from '#/components/ContextMenu' import {type TriggerProps} from '#/components/ContextMenu/types' import {AfterReportDialog} from '#/components/dms/AfterReportDialog' @@ -23,6 +22,7 @@ import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' import {ReportDialog} from '#/components/moderation/ReportDialog' import * as Prompt from '#/components/Prompt' import {usePromptControl} from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {IS_NATIVE} from '#/env' import {EmojiReactionPicker} from './EmojiReactionPicker' @@ -58,7 +58,9 @@ true, ) void Clipboard.setStringAsync(str) - Toast.show(_(msg`Copied to clipboard`), 'clipboard-check') + Toast.show(_(msg`Copied to clipboard`), { + type: 'success', + }) }, [_, message.text, message.facets]) const onPressTranslateMessage = useCallback(() => { @@ -95,11 +97,11 @@ .removeReaction(message.id, emoji) .catch(() => Toast.show(_(msg`Failed to remove emoji reaction`))) } else { if (hasReachedReactionLimit(message, currentAccount?.did)) return - convo - .addReaction(message.id, emoji) - .catch(() => - Toast.show(_(msg`Failed to add emoji reaction`), 'xmark'), - ) + convo.addReaction(message.id, emoji).catch(() => + Toast.show(_(msg`Failed to add emoji reaction`), { + type: 'error', + }), + ) } }, [_, convo, message, currentAccount?.did], diff --git a/src/components/dms/MessageProfileButton.tsx b/src/components/dms/MessageProfileButton.tsx --- a/src/components/dms/MessageProfileButton.tsx +++ b/src/components/dms/MessageProfileButton.tsx @@ -10,11 +10,11 @@ import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' import {type NavigationProp} from '#/lib/routes/types' import {useGetConvoAvailabilityQuery} from '#/state/queries/messages/get-convo-availability' import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' import {canBeMessaged} from '#/components/dms/util' import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' export function MessageProfileButton({ diff --git a/src/components/dms/dialogs/NewChatDialog.tsx b/src/components/dms/dialogs/NewChatDialog.tsx --- a/src/components/dms/dialogs/NewChatDialog.tsx +++ b/src/components/dms/dialogs/NewChatDialog.tsx @@ -7,11 +7,11 @@ import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' import {logger} from '#/logger' import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members' import {FAB} from '#/view/com/util/fab/FAB' -import * as Toast from '#/view/com/util/Toast' import {useTheme} from '#/alf' import * as Dialog from '#/components/Dialog' import {SearchablePeopleList} from '#/components/dialogs/SearchablePeopleList' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' export function NewChat({ @@ -37,7 +37,9 @@ ax.metric('chat:open', {logContext: 'NewChatDialog'}) }, onError: error => { logger.error('Failed to create chat', {safeMessage: error}) - Toast.show(_(msg`An issue occurred starting the chat`), 'xmark') + Toast.show(_(msg`An issue occurred starting the chat`), { + type: 'error', + }) }, }) diff --git a/src/components/dms/dialogs/ShareViaChatDialog.tsx b/src/components/dms/dialogs/ShareViaChatDialog.tsx --- a/src/components/dms/dialogs/ShareViaChatDialog.tsx +++ b/src/components/dms/dialogs/ShareViaChatDialog.tsx @@ -4,9 +4,9 @@ import {useLingui} from '@lingui/react' import {logger} from '#/logger' import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members' -import * as Toast from '#/view/com/util/Toast' import * as Dialog from '#/components/Dialog' import {SearchablePeopleList} from '#/components/dialogs/SearchablePeopleList' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' export function SendViaChatDialog({ @@ -47,10 +47,9 @@ ax.metric('chat:open', {logContext: 'SendViaChatDialog'}) }, onError: error => { logger.error('Failed to share post to chat', {message: error}) - Toast.show( - _(msg`An issue occurred while trying to open the chat`), - 'xmark', - ) + Toast.show(_(msg`An issue occurred while trying to open the chat`), { + type: 'error', + }) }, }) diff --git a/src/components/hooks/useFollowMethods.ts b/src/components/hooks/useFollowMethods.ts --- a/src/components/hooks/useFollowMethods.ts +++ b/src/components/hooks/useFollowMethods.ts @@ -6,7 +6,7 @@ import {logger} from '#/logger' import {type Shadow} from '#/state/cache/types' import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {useRequireAuth} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' +import * as Toast from '#/components/Toast' import {type Metrics} from '#/analytics/metrics' import type * as bsky from '#/types/bsky' @@ -32,7 +32,9 @@ await queueFollow() } catch (e: any) { logger.error(`useFollowMethods: failed to follow`, {message: String(e)}) if (e?.name !== 'AbortError') { - Toast.show(_(msg`An issue occurred, please try again.`), 'xmark') + Toast.show(_(msg`An issue occurred, please try again.`), { + type: 'error', + }) } } }) @@ -47,7 +49,9 @@ logger.error(`useFollowMethods: failed to unfollow`, { message: String(e), }) if (e?.name !== 'AbortError') { - Toast.show(_(msg`An issue occurred, please try again.`), 'xmark') + Toast.show(_(msg`An issue occurred, please try again.`), { + type: 'error', + }) } } }) diff --git a/src/components/moderation/LabelsOnMeDialog.tsx b/src/components/moderation/LabelsOnMeDialog.tsx --- a/src/components/moderation/LabelsOnMeDialog.tsx +++ b/src/components/moderation/LabelsOnMeDialog.tsx @@ -14,11 +14,11 @@ import {makeProfileLink} from '#/lib/routes/links' import {sanitizeHandle} from '#/lib/strings/handles' import {logger} from '#/logger' import {useAgent, useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {InlineLinkText} from '#/components/Link' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_ANDROID} from '#/env' import {Admonition} from '../Admonition' diff --git a/src/components/verification/VerificationCreatePrompt.tsx b/src/components/verification/VerificationCreatePrompt.tsx --- a/src/components/verification/VerificationCreatePrompt.tsx +++ b/src/components/verification/VerificationCreatePrompt.tsx @@ -7,7 +7,6 @@ import {logger} from '#/logger' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useVerificationCreateMutation} from '#/state/queries/verification/useVerificationCreateMutation' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -17,6 +16,7 @@ import {VerifiedCheck} from '#/components/icons/VerifiedCheck' import {Loader} from '#/components/Loader' import * as ProfileCard from '#/components/ProfileCard' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import type * as bsky from '#/types/bsky' export function VerificationCreatePrompt({ diff --git a/src/components/verification/VerificationRemovePrompt.tsx b/src/components/verification/VerificationRemovePrompt.tsx --- a/src/components/verification/VerificationRemovePrompt.tsx +++ b/src/components/verification/VerificationRemovePrompt.tsx @@ -5,9 +5,9 @@ import {useLingui} from '@lingui/react' import {logger} from '#/logger' import {useVerificationsRemoveMutation} from '#/state/queries/verification/useVerificationsRemoveMutation' -import * as Toast from '#/view/com/util/Toast' import {type DialogControlProps} from '#/components/Dialog' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import type * as bsky from '#/types/bsky' export {useDialogControl as usePromptControl} from '#/components/Dialog' @@ -31,7 +31,9 @@ try { await remove({profile, verifications}) Toast.show(_(msg`Removed verification`)) } catch (e) { - Toast.show(_(msg`Failed to remove verification`), 'xmark') + Toast.show(_(msg`Failed to remove verification`), { + type: 'error', + }) logger.error('Failed to remove verification', { safeMessage: e, }) diff --git a/src/features/liveNow/index.tsx b/src/features/liveNow/index.tsx --- a/src/features/liveNow/index.tsx +++ b/src/features/liveNow/index.tsx @@ -23,8 +23,8 @@ useMaybeProfileShadow, } from '#/state/cache/profile-shadow' import {useAgent, useSession} from '#/state/session' import {useTickEveryMinute} from '#/state/shell' -import * as Toast from '#/view/com/util/Toast' import {useDialogContext} from '#/components/Dialog' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {getLiveNowHost, getLiveServiceNames} from '#/features/liveNow/utils' import type * as bsky from '#/types/bsky' diff --git a/src/lib/hooks/useAccountSwitcher.ts b/src/lib/hooks/useAccountSwitcher.ts --- a/src/lib/hooks/useAccountSwitcher.ts +++ b/src/lib/hooks/useAccountSwitcher.ts @@ -5,7 +5,7 @@ import {logger} from '#/logger' import {type SessionAccount, useSessionApi} from '#/state/session' import {useLoggedOutViewControls} from '#/state/shell/logged-out' -import * as Toast from '#/view/com/util/Toast' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {type Metrics} from '#/analytics/metrics' import {IS_WEB} from '#/env' @@ -42,20 +42,18 @@ ax.metric('account:loggedIn', {logContext, withPassword: false}) Toast.show(_(msg`Signed in as @${account.handle}`)) } else { requestSwitchToAccount({requestedAccount: account.did}) - Toast.show( - _(msg`Please sign in as @${account.handle}`), - 'circle-exclamation', - ) + Toast.show(_(msg`Please sign in as @${account.handle}`), { + type: 'warning', + }) } } catch (e: any) { logger.error(`switch account: selectAccount failed`, { message: e.message, }) requestSwitchToAccount({requestedAccount: account.did}) - Toast.show( - _(msg`Please sign in as @${account.handle}`), - 'circle-exclamation', - ) + Toast.show(_(msg`Please sign in as @${account.handle}`), { + type: 'warning', + }) } finally { setPendingDid(null) } diff --git a/src/lib/media/picker.shared.ts b/src/lib/media/picker.shared.ts --- a/src/lib/media/picker.shared.ts +++ b/src/lib/media/picker.shared.ts @@ -6,7 +6,7 @@ } from 'expo-image-picker' import {t} from '@lingui/core/macro' import {type ImageMeta} from '#/state/gallery' -import * as Toast from '#/view/com/util/Toast' +import * as Toast from '#/components/Toast' import {IS_IOS, IS_WEB} from '#/env' import {VIDEO_MAX_DURATION_MS} from '../constants' import {getDataUriSize} from './util' @@ -30,7 +30,9 @@ return (response.assets ?? []) .filter(asset => { if (asset.mimeType?.startsWith('image/')) return true - Toast.show(t`Only image files are supported`, 'exclamation-circle') + Toast.show(t`Only image files are supported`, { + type: 'warning', + }) return false }) .map(image => ({ diff --git a/src/lib/sharing.ts b/src/lib/sharing.ts --- a/src/lib/sharing.ts +++ b/src/lib/sharing.ts @@ -3,7 +3,7 @@ // import * as Sharing from 'expo-sharing' import {setStringAsync} from 'expo-clipboard' import {t} from '@lingui/core/macro' -import * as Toast from '#/view/com/util/Toast' +import * as Toast from '#/components/Toast' import {IS_ANDROID, IS_IOS} from '#/env' /** @@ -21,7 +21,9 @@ } else { // React Native Share is not supported by web. Web Share API // has increasing but not full support, so default to clipboard setStringAsync(url) - Toast.show(t`Copied to clipboard`, 'clipboard-check') + Toast.show(t`Copied to clipboard`, { + type: 'success', + }) } } @@ -37,6 +39,8 @@ if (IS_ANDROID || IS_IOS) { await Share.share({message: text}) } else { await setStringAsync(text) - Toast.show(t`Copied to clipboard`, 'clipboard-check') + Toast.show(t`Copied to clipboard`, { + type: 'success', + }) } } diff --git a/src/screens/List/ListHiddenScreen.tsx b/src/screens/List/ListHiddenScreen.tsx --- a/src/screens/List/ListHiddenScreen.tsx +++ b/src/screens/List/ListHiddenScreen.tsx @@ -19,13 +19,13 @@ type UsePreferencesQueryResponse, useRemoveFeedMutation, } from '#/state/queries/preferences' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {CenteredView} from '#/view/com/util/Views' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' import {Loader} from '#/components/Loader' import {useHider} from '#/components/moderation/Hider' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' export function ListHiddenScreen({ diff --git a/src/screens/Login/ChooseAccountForm.tsx b/src/screens/Login/ChooseAccountForm.tsx --- a/src/screens/Login/ChooseAccountForm.tsx +++ b/src/screens/Login/ChooseAccountForm.tsx @@ -7,11 +7,11 @@ import {logger} from '#/logger' import {type SessionAccount, useSession, useSessionApi} from '#/state/session' import {useLoggedOutViewControls} from '#/state/shell/logged-out' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, web} from '#/alf' import {AccountList} from '#/components/AccountList' import {Button, ButtonText} from '#/components/Button' import * as TextField from '#/components/forms/TextField' +import * as Toast from '#/components/Toast' import {useAnalytics} from '#/analytics' import {IS_WEB} from '#/env' import {FormContainer} from './FormContainer' diff --git a/src/screens/Messages/Inbox.tsx b/src/screens/Messages/Inbox.tsx --- a/src/screens/Messages/Inbox.tsx +++ b/src/screens/Messages/Inbox.tsx @@ -30,7 +30,6 @@ import {useUpdateAllRead} from '#/state/queries/messages/update-all-read' import {FAB} from '#/view/com/util/fab/FAB' import {List} from '#/view/com/util/List' import {ChatListLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' @@ -43,6 +42,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' import {Message_Stroke2_Corner0_Rounded as MessageIcon} from '#/components/icons/Message' import * as Layout from '#/components/Layout' import {ListFooter} from '#/components/Lists' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_NATIVE} from '#/env' import {RequestListItem} from './components/RequestListItem' @@ -313,10 +313,14 @@ const {_} = useLingui() const t = useTheme() const {mutate: markAllRead} = useUpdateAllRead('request', { onMutate: () => { - Toast.show(_(msg`Marked all as read`), 'check') + Toast.show(_(msg`Marked all as read`), { + type: 'success', + }) }, onError: () => { - Toast.show(_(msg`Failed to mark all requests as read`), 'xmark') + Toast.show(_(msg`Failed to mark all requests as read`), { + type: 'error', + }) }, }) @@ -336,10 +340,14 @@ function MarkAsReadHeaderButton() { const {_} = useLingui() const {mutate: markAllRead} = useUpdateAllRead('request', { onMutate: () => { - Toast.show(_(msg`Marked all as read`), 'check') + Toast.show(_(msg`Marked all as read`), { + type: 'success', + }) }, onError: () => { - Toast.show(_(msg`Failed to mark all requests as read`), 'xmark') + Toast.show(_(msg`Failed to mark all requests as read`), { + type: 'error', + }) }, }) diff --git a/src/screens/Messages/Settings.tsx b/src/screens/Messages/Settings.tsx --- a/src/screens/Messages/Settings.tsx +++ b/src/screens/Messages/Settings.tsx @@ -9,12 +9,12 @@ import {type CommonNavigatorParams} from '#/lib/routes/types' import {useUpdateActorDeclaration} from '#/state/queries/messages/actor-declaration' import {useProfileQuery} from '#/state/queries/profile' import {useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a} from '#/alf' import {Admonition} from '#/components/Admonition' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' import * as Layout from '#/components/Layout' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {IS_NATIVE} from '#/env' import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' @@ -37,7 +37,9 @@ const {preferences, setPref} = useBackgroundNotificationPreferences() const {mutate: updateDeclaration} = useUpdateActorDeclaration({ onError: () => { - Toast.show(_(msg`Failed to update settings`), 'xmark') + Toast.show(_(msg`Failed to update settings`), { + type: 'error', + }) }, }) diff --git a/src/screens/Messages/components/ChatDisabled.tsx b/src/screens/Messages/components/ChatDisabled.tsx --- a/src/screens/Messages/components/ChatDisabled.tsx +++ b/src/screens/Messages/components/ChatDisabled.tsx @@ -9,11 +9,11 @@ import {BLUESKY_MOD_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' import {useAgent, useSession} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' export function ChatDisabled() { @@ -97,7 +97,9 @@ ) }, onError: err => { logger.error('Failed to submit chat appeal', {message: err}) - Toast.show(_(msg`Failed to submit appeal, please try again.`), 'xmark') + Toast.show(_(msg`Failed to submit appeal, please try again.`), { + type: 'error', + }) }, onSuccess: () => { control.close() diff --git a/src/screens/Messages/components/MessageInput.tsx b/src/screens/Messages/components/MessageInput.tsx --- a/src/screens/Messages/components/MessageInput.tsx +++ b/src/screens/Messages/components/MessageInput.tsx @@ -24,10 +24,10 @@ useMessageDraft, useSaveMessageDraft, } from '#/state/messages/message-drafts' import {type EmojiPickerPosition} from '#/view/com/composer/text-input/web/EmojiPicker' -import * as Toast from '#/view/com/util/Toast' import {android, atoms as a, useTheme} from '#/alf' import {useSharedInputStyles} from '#/components/forms/TextField' import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' +import * as Toast from '#/components/Toast' import {IS_IOS, IS_WEB} from '#/env' import {useExtractEmbedFromFacets} from './MessageInputEmbed' @@ -76,7 +76,9 @@ if (!hasEmbed && message.trim() === '') { return } if (countGraphemes(message) > MAX_DM_GRAPHEME_LENGTH) { - Toast.show(_(msg`Message is too long`), 'xmark') + Toast.show(_(msg`Message is too long`), { + type: 'error', + }) return } clearDraft() diff --git a/src/screens/Messages/components/MessageInput.web.tsx b/src/screens/Messages/components/MessageInput.web.tsx --- a/src/screens/Messages/components/MessageInput.web.tsx +++ b/src/screens/Messages/components/MessageInput.web.tsx @@ -17,12 +17,12 @@ import { type Emoji, type EmojiPickerPosition, } from '#/view/com/composer/text-input/web/EmojiPicker' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, flatten, useTheme} from '#/alf' import {Button} from '#/components/Button' import {useSharedInputStyles} from '#/components/forms/TextField' import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji' import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlane} from '#/components/icons/PaperPlane' +import * as Toast from '#/components/Toast' import {IS_WEB_SAFARI, IS_WEB_TOUCH_DEVICE} from '#/env' import {useExtractEmbedFromFacets} from './MessageInputEmbed' @@ -57,7 +57,9 @@ if (!hasEmbed && message.trim() === '') { return } if (countGraphemes(message) > MAX_DM_GRAPHEME_LENGTH) { - Toast.show(_(msg`Message is too long`), 'xmark') + Toast.show(_(msg`Message is too long`), { + type: 'error', + }) return } clearDraft() diff --git a/src/screens/Messages/components/RequestButtons.tsx b/src/screens/Messages/components/RequestButtons.tsx --- a/src/screens/Messages/components/RequestButtons.tsx +++ b/src/screens/Messages/components/RequestButtons.tsx @@ -16,7 +16,6 @@ import { unstableCacheProfileView, useProfileBlockMutationQueue, } from '#/state/queries/profile' -import * as Toast from '#/view/com/util/Toast' import {atoms as a} from '#/alf' import { Button, @@ -36,6 +35,7 @@ import {PersonX_Stroke2_Corner0_Rounded as PersonXIcon} from '#/components/icons/Person' import {Loader} from '#/components/Loader' import * as Menu from '#/components/Menu' import {ReportDialog} from '#/components/moderation/ReportDialog' +import * as Toast from '#/components/Toast' export function RejectMenu({ convo, @@ -72,7 +72,9 @@ context: 'toast', message: 'Failed to delete chat', }), ), - 'xmark', + { + type: 'error', + }, ) }, }) @@ -86,7 +88,9 @@ context: 'toast', message: 'Chat deleted', }), ), - 'check', + { + type: 'success', + }, ) leaveConvo() }, [leaveConvo, _]) @@ -99,7 +103,9 @@ context: 'toast', message: 'Account blocked', }), ), - 'check', + { + type: 'success', + }, ) // block and also delete convo queueBlock() @@ -245,7 +251,9 @@ context: 'toast', message: 'Failed to accept chat', }), ), - 'xmark', + { + type: 'error', + }, ) }, }) @@ -314,7 +322,9 @@ context: 'toast', message: 'Failed to delete chat', }), ), - 'xmark', + { + type: 'error', + }, ) }, }) @@ -327,7 +337,9 @@ context: 'toast', message: 'Chat deleted', }), ), - 'check', + { + type: 'success', + }, ) leaveConvo() }, [leaveConvo, _]) diff --git a/src/screens/ModerationInteractionSettings/index.tsx b/src/screens/ModerationInteractionSettings/index.tsx --- a/src/screens/ModerationInteractionSettings/index.tsx +++ b/src/screens/ModerationInteractionSettings/index.tsx @@ -16,12 +16,12 @@ import { threadgateAllowUISettingToAllowRecordValue, threadgateRecordToAllowUISetting, } from '#/state/queries/threadgate' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useGutters} from '#/alf' import {Admonition} from '#/components/Admonition' import {PostInteractionSettingsForm} from '#/components/dialogs/PostInteractionSettingsDialog' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' export function Screen() { const gutters = useGutters(['base']) diff --git a/src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx b/src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx --- a/src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx @@ -12,11 +12,11 @@ useProfileFollowMutationQueue, useProfileQuery, } from '#/state/queries/profile' import {useRequireAuth} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' +import * as Toast from '#/components/Toast' import {IS_IOS} from '#/env' import {GrowthHack} from './GrowthHack' @@ -114,7 +114,9 @@ await queueFollow() } catch (e: any) { if (e?.name !== 'AbortError') { logger.error('Failed to follow', {message: String(e)}) - Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark') + Toast.show(_(msg`There was an issue! ${e.toString()}`), { + type: 'error', + }) } } }) @@ -125,7 +127,9 @@ await queueUnfollow() } catch (e: any) { if (e?.name !== 'AbortError') { logger.error('Failed to unfollow', {message: String(e)}) - Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark') + Toast.show(_(msg`There was an issue! ${e.toString()}`), { + type: 'error', + }) } } }) diff --git a/src/screens/Profile/Header/EditProfileDialog.tsx b/src/screens/Profile/Header/EditProfileDialog.tsx --- a/src/screens/Profile/Header/EditProfileDialog.tsx +++ b/src/screens/Profile/Header/EditProfileDialog.tsx @@ -12,7 +12,6 @@ import {logger} from '#/logger' import {type ImageMeta} from '#/state/gallery' import {useProfileUpdateMutation} from '#/state/queries/profile' import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' -import * as Toast from '#/view/com/util/Toast' import {EditableUserAvatar} from '#/view/com/util/UserAvatar' import {UserBanner} from '#/view/com/util/UserBanner' import {atoms as a, useTheme} from '#/alf' @@ -23,6 +22,7 @@ import * as TextField from '#/components/forms/TextField' import {InlineLinkText} from '#/components/Link' import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useSimpleVerificationState} from '#/components/verification' diff --git a/src/screens/Profile/components/ProfileFeedHeader.tsx b/src/screens/Profile/components/ProfileFeedHeader.tsx --- a/src/screens/Profile/components/ProfileFeedHeader.tsx +++ b/src/screens/Profile/components/ProfileFeedHeader.tsx @@ -21,7 +21,6 @@ useUpdateSavedFeedsMutation, } from '#/state/queries/preferences' import {useSession} from '#/state/session' import {formatCount} from '#/view/com/util/numeric/format' -import * as Toast from '#/view/com/util/Toast' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -50,6 +49,7 @@ ReportDialog, useReportDialogControl, } from '#/components/moderation/ReportDialog' import {RichText} from '#/components/RichText' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_WEB} from '#/env' @@ -139,7 +139,9 @@ Toast.show( _( msg`There was an issue updating your feeds, please check your internet connection and try again.`, ), - 'xmark', + { + type: 'error', + }, ) logger.error('Failed to update feeds', {message: err}) } @@ -177,7 +179,9 @@ Toast.show(_(msg`Pinned ${info.displayName} to Home`)) ax.metric('feed:pin', {feedUrl: info.uri}) } } catch (e) { - Toast.show(_(msg`There was an issue contacting the server`), 'xmark') + Toast.show(_(msg`There was an issue contacting the server`), { + type: 'error', + }) logger.error('Failed to toggle pinned feed', {message: e}) } } @@ -421,7 +425,9 @@ Toast.show( _( msg`There was an issue contacting the server, please check your internet connection and try again.`, ), - 'xmark', + { + type: 'error', + }, ) logger.error('Failed to toggle like', {message: err}) } diff --git a/src/screens/SavedFeeds.tsx b/src/screens/SavedFeeds.tsx --- a/src/screens/SavedFeeds.tsx +++ b/src/screens/SavedFeeds.tsx @@ -25,7 +25,6 @@ } from '#/state/queries/preferences' import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' import {useSetMinimalShellMode} from '#/state/shell' import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' -import * as Toast from '#/view/com/util/Toast' import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' import {atoms as a, useBreakpoints, useTheme} from '#/alf' @@ -43,6 +42,7 @@ import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' import * as Layout from '#/components/Layout' import {InlineLinkText} from '#/components/Link' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' type Props = NativeStackScreenProps @@ -104,7 +104,9 @@ } else { navigation.navigate('Feeds') } } catch (e) { - Toast.show(_(msg`There was an issue contacting the server`), 'xmark') + Toast.show(_(msg`There was an issue contacting the server`), { + type: 'error', + }) logger.error('Failed to toggle pinned feed', {message: e}) } } @@ -288,7 +290,9 @@ } else { navigation.navigate('Feeds') } } catch (e) { - Toast.show(_(msg`There was an issue contacting the server`), 'xmark') + Toast.show(_(msg`There was an issue contacting the server`), { + type: 'error', + }) logger.error('Failed to toggle pinned feed', {message: e}) } } diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -10,7 +10,6 @@ import {useMutation} from '@tanstack/react-query' import {STATUS_PAGE_URL} from '#/lib/constants' import {type CommonNavigatorParams} from '#/lib/routes/types' -import * as Toast from '#/view/com/util/Toast' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom' import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/components/icons/BroomSparkle' @@ -20,6 +19,7 @@ import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/icons/Newspaper' import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {getDeviceId} from '#/analytics/identifiers' import {IS_ANDROID, IS_IOS, IS_NATIVE} from '#/env' import * as env from '#/env' diff --git a/src/screens/Settings/AppPasswords.tsx b/src/screens/Settings/AppPasswords.tsx --- a/src/screens/Settings/AppPasswords.tsx +++ b/src/screens/Settings/AppPasswords.tsx @@ -20,7 +20,6 @@ useAppPasswordsQuery, } from '#/state/queries/app-passwords' import {EmptyState} from '#/view/com/util/EmptyState' import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -32,6 +31,7 @@ import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {AddAppPasswordDialog} from './components/AddAppPasswordDialog' import * as SettingsList from './components/SettingsList' diff --git a/src/screens/Settings/InterestsSettings.tsx b/src/screens/Settings/InterestsSettings.tsx --- a/src/screens/Settings/InterestsSettings.tsx +++ b/src/screens/Settings/InterestsSettings.tsx @@ -22,13 +22,13 @@ import {createGetSuggestedFeedsQueryKey} from '#/state/queries/trending/useGetSuggestedFeedsQuery' import {createGetSuggestedUsersQueryKey} from '#/state/queries/trending/useGetSuggestedUsersQuery' import {createSuggestedStarterPacksQueryKey} from '#/state/queries/useSuggestedStarterPacksQuery' import {useAgent} from '#/state/session' -import * as Toast from '#/view/com/util/Toast' import {atoms as a, useGutters, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' type Props = NativeStackScreenProps @@ -139,7 +139,9 @@ message: 'Failed to save your interests.', context: 'toast', }), ), - 'xmark', + { + type: 'error', + }, ) } finally { setIsSaving(false) diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -28,7 +28,6 @@ import {type SessionAccount, useSession, useSessionApi} from '#/state/session' import {useOnboardingDispatch} from '#/state/shell' import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useCloseAllActiveElements} from '#/state/util' -import * as Toast from '#/view/com/util/Toast' import {UserAvatar} from '#/view/com/util/UserAvatar' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {atoms as a, platform, tokens, useBreakpoints, useTheme} from '#/alf' @@ -63,6 +62,7 @@ import * as Menu from '#/components/Menu' import {ID as PolicyUpdate202508} from '#/components/PolicyUpdateOverlay/updates/202508/config' import {ProfileBadges} from '#/components/ProfileBadges' import * as Prompt from '#/components/Prompt' +import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' import {useAnalytics} from '#/analytics' import {IS_INTERNAL, IS_IOS, IS_NATIVE} from '#/env' @@ -520,7 +520,6 @@ Unapply Pull Request {currentChannel} ) : null} - @@ -545,7 +544,9 @@