diff --git a/packages/web/components/templates/article/HighlightNoteModal.tsx b/packages/web/components/templates/article/HighlightNoteModal.tsx index e94213733..a39209a0c 100644 --- a/packages/web/components/templates/article/HighlightNoteModal.tsx +++ b/packages/web/components/templates/article/HighlightNoteModal.tsx @@ -17,7 +17,7 @@ import { readableUpdatedAtMessage } from './../../../lib/dateFormatting' import { useConfirmListener } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts' import { createHighlight } from '../../../lib/highlights/createHighlight' import { createHighlightMutation } from '../../../lib/networking/mutations/createHighlightMutation' -import toast from 'react-hot-toast' +import { showErrorToast } from '../../../lib/toastHelpers' type HighlightNoteModalProps = { author: string @@ -59,14 +59,14 @@ export function HighlightNoteModal( props.onUpdate({ ...props.highlight, annotation: noteContent }) props.onOpenChange(false) } else { - toast.error('Error updating your note', { position: 'bottom-right' }) + showErrorToast('Error updating your note', { position: 'bottom-right' }) } } if (!props.highlight && props.createHighlightForNote) { const result = await props.createHighlightForNote(noteContent) if (result) { props.onOpenChange(true) } else { - toast.error('Error saving highlight', { position: 'bottom-right' }) + showErrorToast('Error saving highlight', { position: 'bottom-right' }) } } else { props.onOpenChange(false) diff --git a/packages/web/components/templates/article/HighlightsLayer.tsx b/packages/web/components/templates/article/HighlightsLayer.tsx index be622a01f..b25cc0937 100644 --- a/packages/web/components/templates/article/HighlightsLayer.tsx +++ b/packages/web/components/templates/article/HighlightsLayer.tsx @@ -18,7 +18,7 @@ import { ShareHighlightModal } from './ShareHighlightModal' import { HighlightPostToFeedModal } from './HighlightPostToFeedModal' import { HighlightsModal } from './HighlightsModal' import { useCanShareNative } from '../../../lib/hooks/useCanShareNative' -import toast from 'react-hot-toast' +import { showErrorToast } from '../../../lib/toastHelpers' import { ArticleMutations } from '../../../lib/articleActions' type HighlightsLayerProps = { @@ -220,7 +220,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element { annotation ) if (!result) { - toast.error('Error saving highlight', { position: 'bottom-right' }) + showErrorToast('Error saving highlight', { position: 'bottom-right' }) } // if (successAction === 'share' && canShareNative) { // handleNativeShare(highlight.shortId) diff --git a/packages/web/components/templates/article/SnoozeLinkModal.tsx b/packages/web/components/templates/article/SnoozeLinkModal.tsx index c13958803..68167820e 100644 --- a/packages/web/components/templates/article/SnoozeLinkModal.tsx +++ b/packages/web/components/templates/article/SnoozeLinkModal.tsx @@ -4,7 +4,7 @@ import { Button } from '../../elements/Button' import { StyledText } from '../../elements/StyledText' import { X, Check } from 'phosphor-react' import { useState } from 'react' -import toast from 'react-hot-toast' +import { showErrorToast } from '../../../lib/toastHelpers' type ShareArticleModalProps = { onOpenChange: (open: boolean) => void @@ -149,7 +149,7 @@ export function SnoozeLinkModal( props.submit(snoozeOption, sendReminder, msg) props.onOpenChange(false) } else { - toast.error('No option selected', { position: 'bottom-right' }) + showErrorToast('No option selected', { position: 'bottom-right' }) } }} >Save @@ -158,4 +158,4 @@ export function SnoozeLinkModal( ) -} \ No newline at end of file +} diff --git a/packages/web/components/templates/homeFeed/AddLinkModal.tsx b/packages/web/components/templates/homeFeed/AddLinkModal.tsx index 1246b0341..162eb147c 100644 --- a/packages/web/components/templates/homeFeed/AddLinkModal.tsx +++ b/packages/web/components/templates/homeFeed/AddLinkModal.tsx @@ -13,6 +13,7 @@ import { useState, useCallback } from 'react' import { createArticleFromURLMutation } from '../../../lib/networking/mutations/createArticleFromURLMutation' import { saveUrlMutation } from '../../../lib/networking/mutations/saveUrlMutation' import toast from 'react-hot-toast' +import { showErrorToast } from '../../../lib/toastHelpers' type AddLinkModalProps = { onOpenChange: (open: boolean) => void @@ -42,7 +43,7 @@ export function AddLinkModal(props: AddLinkModalProps): JSX.Element { ), { position: 'bottom-right' }) } else { - toast.error('Error saving link', { position: 'bottom-right' }) + showErrorToast('Error saving link', { position: 'bottom-right' }) } }, [link]) @@ -100,7 +101,7 @@ export function AddLinkModal(props: AddLinkModalProps): JSX.Element { // `https` to give the link a protocol. const newLink = `https://${link}` if (!validateLink(newLink)) { - toast.error('Invalid link', { position: 'bottom-right' }) + showErrorToast('Invalid link', { position: 'bottom-right' }) return } setLink(newLink) diff --git a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx index 36c2371c4..7fe8339df 100644 --- a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx +++ b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx @@ -27,7 +27,7 @@ import { ShareArticleModal } from '../article/ShareArticleModal' import { userPersonalizationMutation } from '../../../lib/networking/mutations/userPersonalizationMutation' import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences' import { webBaseURL } from '../../../lib/appConfig' -import toast, { Toaster } from 'react-hot-toast' +import { Toaster } from 'react-hot-toast' import { SnoozeLinkModal } from '../article/SnoozeLinkModal' import { createReminderMutation, @@ -35,6 +35,7 @@ import { } from '../../../lib/networking/mutations/createReminderMutation' import { useFetchMoreScroll } from '../../../lib/hooks/useFetchMoreScroll' import { usePersistedState } from '../../../lib/hooks/usePersistedState' +import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers' export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT' @@ -675,10 +676,10 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element { return props.actionHandler('archive', props.snoozeTarget) }) .then(() => { - toast.success(msg, { position: 'bottom-right' }) + showSuccessToast(msg, { position: 'bottom-right' }) }) .catch((error) => { - toast.error('There was an error snoozing your link.', { + showErrorToast('There was an error snoozing your link.', { position: 'bottom-right', }) }) diff --git a/packages/web/lib/toastHelpers.tsx b/packages/web/lib/toastHelpers.tsx new file mode 100644 index 000000000..ea76bb39b --- /dev/null +++ b/packages/web/lib/toastHelpers.tsx @@ -0,0 +1,64 @@ +import { toast, ToastOptions } from 'react-hot-toast' +import { CheckCircle, WarningCircle, X } from 'phosphor-react' +import { Box, HStack } from '../components/elements/LayoutPrimitives' +import { styled } from '@stitches/react' + +const toastStyles = { + minWidth: 265, + height: 56, + borderRadius: 4, + boxShadow: '0px 2px 8px rgba(32, 31, 29, 0.33)', + margin: 0, + paddingLeft: 6, + paddingRight: 6, + paddingTop: 12, + paddingBottom: 12, +} + +const messageStyles = { + fontSize: 16, + fontWeight: 'bolder', + color: 'white', + flex: 1, + marginLeft: 16, +} + +const MessageContainer = styled(Box, messageStyles) +const FullWidthContainer = styled(HStack, { + width: '100%', +}) + +type ToastType = 'success' | 'error' + +const showToast = ( + message: string, + background: string, + type: ToastType, + options?: ToastOptions +) => { + return toast( + ({ id }) => ( + + {type === 'success' ? : } + {message} + + toast.dismiss(id)} /> + + + ), + { + style: { + ...toastStyles, + background: background, + }, + ...options, + }) +} + +export const showSuccessToast = (message: string, options?: ToastOptions) => { + return showToast(message, '#55B938', 'success', options) +} + +export const showErrorToast = (message: string, options?: ToastOptions) => { + return showToast(message, '#cc0000', 'error', options) +} diff --git a/packages/web/pages/settings/emails.tsx b/packages/web/pages/settings/emails.tsx index befc50bf9..76e4697f7 100644 --- a/packages/web/pages/settings/emails.tsx +++ b/packages/web/pages/settings/emails.tsx @@ -22,6 +22,7 @@ import { toast, Toaster } from 'react-hot-toast' import { useCallback } from 'react' import { StyledText } from '../../components/elements/StyledText' import { applyStoredTheme } from '../../lib/themeUpdater' +import { showSuccessToast } from '../../lib/toastHelpers' import Link from 'next/link' enum TextType { @@ -165,11 +166,7 @@ function CopyTextButton(props: CopyTextButtonProps): JSX.Element { const copy = useCallback(() => { copyLink() - toast( - props.type == TextType.EmailAddress - ? 'Email Address Copied' - : 'Confirmation Code Copied' - ) + showSuccessToast(props.type == TextType.EmailAddress ? 'Email Address Copied' : 'Confirmation Code Copied'); }, []) return ( @@ -186,14 +183,14 @@ export default function EmailsPage(): JSX.Element { applyStoredTheme(false) async function createEmail(): Promise { + showSuccessToast('Email Created!') await createNewsletterEmailMutation() revalidate() - toast.success('Email Created') } async function deleteEmail(id: string): Promise { await deleteNewsletterEmailMutation(id) revalidate() - toast.success('Email Deleted!') + showSuccessToast('Email Deleted!') } return ( diff --git a/packages/web/pages/settings/labels.tsx b/packages/web/pages/settings/labels.tsx index 4254fbdfa..64f0916ad 100644 --- a/packages/web/pages/settings/labels.tsx +++ b/packages/web/pages/settings/labels.tsx @@ -1,12 +1,13 @@ import { PrimaryLayout } from '../../components/templates/PrimaryLayout' import { Button } from '../../components/elements/Button' import { Box, VStack } from '../../components/elements/LayoutPrimitives' -import { toast, Toaster } from 'react-hot-toast' +import { Toaster } from 'react-hot-toast' import { useGetLabelsQuery } from '../../lib/networking/queries/useGetLabelsQuery' import { createLabelMutation } from '../../lib/networking/mutations/createLabelMutation' import { deleteLabelMutation } from '../../lib/networking/mutations/deleteLabelMutation' import { useState } from 'react' import { applyStoredTheme } from '../../lib/themeUpdater' +import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' export default function LabelsPage(): JSX.Element { const { labels, revalidate, isValidating } = useGetLabelsQuery() @@ -20,16 +21,16 @@ export default function LabelsPage(): JSX.Element { const res = await createLabelMutation(name, color, description) if (res) { if (res.createLabel.errorCodes && res.createLabel.errorCodes.length > 0) { - toast.error(res.createLabel.errorCodes[0]) + showErrorToast(res.createLabel.errorCodes[0]) } else { - toast.success('Label created') + showSuccessToast('Label created') setName('') setColor('') setDescription('') revalidate() } } else { - toast.error('Failed to create label') + showErrorToast('Failed to create label') } }