diff --git a/packages/shared/src/components/SharedByUserBanner.tsx b/packages/shared/src/components/SharedByUserBanner.tsx
deleted file mode 100644
index 0a8aec8589..0000000000
--- a/packages/shared/src/components/SharedByUserBanner.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import type { ReactElement } from 'react';
-import React from 'react';
-import { useRouter } from 'next/router';
-import classNames from 'classnames';
-import { useAuthContext } from '../contexts/AuthContext';
-import { ProfileImageSize, ProfilePicture } from './ProfilePicture';
-import {
- Typography,
- TypographyColor,
- TypographyType,
-} from './typography/Typography';
-import { FollowButton } from './contentPreference/FollowButton';
-import { ContentPreferenceType } from '../graphql/contentPreference';
-import { Origin } from '../lib/log';
-import type { WithClassNameProps } from './utilities';
-import { useUserShortByIdQuery } from '../hooks/user/useUserShortByIdQuery';
-import { useContentPreferenceStatusQuery } from '../hooks/contentPreference/useContentPreferenceStatusQuery';
-
-export const SharedByUserBanner = ({
- className,
-}: WithClassNameProps): ReactElement => {
- const { user: currentUser } = useAuthContext();
- const { query } = useRouter();
- const userid = (query?.userid as string) || null;
-
- const { data: contentPreference } = useContentPreferenceStatusQuery({
- id: userid,
- entity: ContentPreferenceType.User,
- queryOptions: { enabled: !!userid && userid !== currentUser?.id },
- });
- const { data: user } = useUserShortByIdQuery({ id: userid });
- if (!userid || userid === currentUser?.id || !user) {
- return null;
- }
-
- return (
-
-
-
- {user.name} Shared this post
-
-
-
- );
-};
diff --git a/packages/shared/src/components/post/PostContent.tsx b/packages/shared/src/components/post/PostContent.tsx
index 8e08127666..61e9a91930 100644
--- a/packages/shared/src/components/post/PostContent.tsx
+++ b/packages/shared/src/components/post/PostContent.tsx
@@ -24,7 +24,6 @@ import { cloudinaryPostImageCoverPlaceholder } from '../../lib/image';
import { withPostById } from './withPostById';
import { PostClickbaitShield } from './common/PostClickbaitShield';
import { useSmartTitle } from '../../hooks/post/useSmartTitle';
-import { SharedByUserBanner } from '../SharedByUserBanner';
import { SmartPrompt } from './smartPrompts/SmartPrompt';
import { PostTagList } from './tags/PostTagList';
@@ -147,7 +146,6 @@ export function PostContentRaw({
origin={origin}
post={post}
>
-
-
-
Promise
) | (() => unknown);
interface UseToastNotification {
- displayToast: (message: string, params?: NotifyOptionalProps) => void;
+ displayToast: (
+ message: string | ReactNode,
+ params?: NotifyOptionalProps,
+ ) => void;
dismissToast: () => void;
subject?: ToastSubject;
}
@@ -15,7 +19,7 @@ export enum ToastSubject {
}
export interface ToastNotification {
- message: string;
+ message: string | ReactNode;
timer: number;
subject?: ToastSubject;
onUndo?: AnyFunction;
@@ -39,7 +43,7 @@ export const useToastNotification = (): UseToastNotification => {
client.setQueryData(TOAST_NOTIF_KEY, data);
const displayToast = (
- message: string,
+ message: string | ReactNode,
{ timer = 5000, ...props }: NotifyOptionalProps = {},
) => setToastNotification({ message, timer, ...props });
diff --git a/packages/webapp/hooks/useSharedByToast.tsx b/packages/webapp/hooks/useSharedByToast.tsx
new file mode 100644
index 0000000000..ef9c37834c
--- /dev/null
+++ b/packages/webapp/hooks/useSharedByToast.tsx
@@ -0,0 +1,116 @@
+import React, { useEffect, useRef } from 'react';
+import { useRouter } from 'next/router';
+import Link from 'next/link';
+import { useAuthContext } from '@dailydotdev/shared/src/contexts/AuthContext';
+import { useToastNotification } from '@dailydotdev/shared/src/hooks/useToastNotification';
+import { useContentPreferenceStatusQuery } from '@dailydotdev/shared/src/hooks/contentPreference/useContentPreferenceStatusQuery';
+import {
+ ContentPreferenceStatus,
+ ContentPreferenceType,
+} from '@dailydotdev/shared/src/graphql/contentPreference';
+import { useUserShortByIdQuery } from '@dailydotdev/shared/src/hooks/user/useUserShortByIdQuery';
+import { useContentPreference } from '@dailydotdev/shared/src/hooks/contentPreference/useContentPreference';
+import { ButtonSize } from '@dailydotdev/shared/src/components/buttons/common';
+import {
+ ProfileImageSize,
+ ProfilePicture,
+} from '@dailydotdev/shared/src/components/ProfilePicture';
+import { Button } from '@dailydotdev/shared/src/components/buttons/Button';
+import {
+ Typography,
+ TypographyTag,
+ TypographyType,
+} from '@dailydotdev/shared/src/components/typography/Typography';
+
+const useSharedByToast = (): void => {
+ const hasShownToast = useRef(false);
+ const { user: currentUser, isAuthReady } = useAuthContext();
+ const { query } = useRouter();
+ const userId = (query?.userid as string) || null;
+ const isSameUser = !!userId && userId === currentUser?.id;
+ const { data: contentPreference, isPending } =
+ useContentPreferenceStatusQuery({
+ id: userId,
+ entity: ContentPreferenceType.User,
+ });
+ const { data: user } = useUserShortByIdQuery({ id: userId });
+ const { follow } = useContentPreference({ showToastOnSuccess: true });
+ const { displayToast, dismissToast } = useToastNotification();
+ const isDataReady = isAuthReady || (currentUser && !isPending);
+
+ useEffect(() => {
+ if (
+ !user ||
+ isSameUser ||
+ !isDataReady ||
+ hasShownToast.current ||
+ contentPreference?.status === ContentPreferenceStatus.Blocked
+ ) {
+ return undefined;
+ }
+
+ const showFollow =
+ !!currentUser &&
+ contentPreference?.status !== ContentPreferenceStatus.Follow;
+
+ const timeout = setTimeout(() => {
+ hasShownToast.current = true;
+ displayToast(
+
+
dismissToast()}
+ className="flex items-center gap-2 "
+ href={`/${user.username}`}
+ >
+
+
+
+ {user.name}
+ {' '}
+
+ shared this post
+
+
+
+ {showFollow && (
+
+ )}
+
,
+ );
+ // Set a small timeout to ensure its shown after the page is loaded and won't be cleared by updates.
+ }, 1000);
+
+ return () => clearTimeout(timeout);
+ }, [
+ user,
+ contentPreference?.status,
+ hasShownToast,
+ displayToast,
+ dismissToast,
+ follow,
+ isSameUser,
+ isDataReady,
+ currentUser,
+ ]);
+};
+
+export default useSharedByToast;
diff --git a/packages/webapp/pages/posts/[id]/index.tsx b/packages/webapp/pages/posts/[id]/index.tsx
index 96f10470f8..4616b5526d 100644
--- a/packages/webapp/pages/posts/[id]/index.tsx
+++ b/packages/webapp/pages/posts/[id]/index.tsx
@@ -41,6 +41,7 @@ import {
PostSEOSchema,
} from '../../../components/PostSEOSchema';
import type { DynamicSeoProps } from '../../../components/common';
+import useSharedByToast from '../../../hooks/useSharedByToast';
const Unauthorized = dynamic(
() =>
@@ -124,6 +125,7 @@ export const PostPage = ({ id, initialData, error }: Props): ReactElement => {
[PostType.Share, PostType.Welcome, PostType.Freeform].includes(post?.type),
featureTheme && 'bg-transparent',
);
+ useSharedByToast();
useScrollTopOffset(() => globalThis.window, {
onOverOffset: () => position !== 'fixed' && setPosition('fixed'),