diff --git a/packages/extension/package.json b/packages/extension/package.json index 10cc7be750..69612c4e2e 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "extension", - "version": "3.36.8", + "version": "3.36.9", "scripts": { "dev:chrome": "cross-env NODE_ENV=development cross-env TARGET_BROWSER=chrome webpack --watch", "dev:firefox": "cross-env NODE_ENV=development cross-env TARGET_BROWSER=firefox webpack --watch", diff --git a/packages/extension/webpack.config.js b/packages/extension/webpack.config.js index 884bc3667e..db3008b459 100644 --- a/packages/extension/webpack.config.js +++ b/packages/extension/webpack.config.js @@ -53,6 +53,7 @@ const baseConfig = { extensions: ['.svg', '.ts', '.tsx', '.js', '.json'], alias: { 'react-onesignal': false, + '@marsidev/react-turnstile': false, }, fallback: { fs: false, diff --git a/packages/shared/src/components/CustomFeedOptionsMenu.tsx b/packages/shared/src/components/CustomFeedOptionsMenu.tsx index 1985b260f8..e9ce4046f5 100644 --- a/packages/shared/src/components/CustomFeedOptionsMenu.tsx +++ b/packages/shared/src/components/CustomFeedOptionsMenu.tsx @@ -20,6 +20,7 @@ type CustomFeedOptionsMenuProps = { onUndo?: (feedId: string) => void; className?: string; shareProps: UseShareOrCopyLinkProps; + additionalOptions?: MenuItemProps[]; }; const CustomFeedOptionsMenu = ({ @@ -28,6 +29,7 @@ const CustomFeedOptionsMenu = ({ onAdd, onUndo, onCreateNewFeed, + additionalOptions = [], }: CustomFeedOptionsMenuProps): ReactElement => { const { showPlusSubscription } = usePlusSubscription(); const { openModal } = useLazyModal(); @@ -57,14 +59,17 @@ const CustomFeedOptionsMenu = ({ label: 'Share', action: () => onShareOrCopyLink(), }, - { + ]; + + if (showPlusSubscription) { + options.push({ icon: , label: 'Add to custom feed', action: handleOpenModal, - }, - ]; + }); + } - if (!showPlusSubscription) { + if (additionalOptions.length === 0 && !showPlusSubscription) { return ( + ); +}; + +export default BlockButton; diff --git a/packages/shared/src/components/contentPreference/FollowButton.tsx b/packages/shared/src/components/contentPreference/FollowButton.tsx index ba47a27b00..13d401f702 100644 --- a/packages/shared/src/components/contentPreference/FollowButton.tsx +++ b/packages/shared/src/components/contentPreference/FollowButton.tsx @@ -95,10 +95,15 @@ export const FollowButton = ({ return null; } + const isFollowing = [ + ContentPreferenceStatus.Subscribed, + ContentPreferenceStatus.Follow, + ].includes(currentStatus); + return (
{ @@ -108,7 +113,7 @@ export const FollowButton = ({ }} copyType={copyType} /> - {!!currentStatus && showSubscribe && ( + {isFollowing && showSubscribe && ( ); }; diff --git a/packages/shared/src/components/feeds/FeedSettings/components/BlockedTagList.tsx b/packages/shared/src/components/feeds/FeedSettings/components/BlockedTagList.tsx index 15faf8f3f1..f7ea7c51cc 100644 --- a/packages/shared/src/components/feeds/FeedSettings/components/BlockedTagList.tsx +++ b/packages/shared/src/components/feeds/FeedSettings/components/BlockedTagList.tsx @@ -51,6 +51,8 @@ export const BlockedTagList = ({ canFetchMore: checkFetchMore(queryResult), fetchNextPage, }} + showBlock + showFollow={false} /> ); }; diff --git a/packages/shared/src/components/feeds/FeedSettings/components/BlockedUserList.tsx b/packages/shared/src/components/feeds/FeedSettings/components/BlockedUserList.tsx index d60ce7ed72..ebf3b65a37 100644 --- a/packages/shared/src/components/feeds/FeedSettings/components/BlockedUserList.tsx +++ b/packages/shared/src/components/feeds/FeedSettings/components/BlockedUserList.tsx @@ -7,7 +7,7 @@ import { checkFetchMore } from '../../../containers/InfiniteScrolling'; import { Origin } from '../../../../lib/log'; import { CopyType } from '../../../sources/SourceActions/SourceActionsFollow'; import { useBlockedQuery } from '../../../../hooks/contentPreference/useBlockedQuery'; -import { anchorDefaultRel } from '../../../../lib/strings'; +import BlockButton from '../../../contentPreference/BlockButton'; type BlockedUserListProps = { searchQuery?: string; @@ -52,14 +52,22 @@ export const BlockedUserList = ({ canFetchMore: checkFetchMore(queryResult), fetchNextPage, }} + additionalContent={(user) => ( + + )} userInfoProps={{ origin: Origin.BlockedFilter, - showFollow: true, + showFollow: false, showSubscribe: false, copyType: CopyType.Custom, feedId: feed.id, - rel: anchorDefaultRel, - target: '_blank', }} /> ); diff --git a/packages/shared/src/components/modals/common.tsx b/packages/shared/src/components/modals/common.tsx index f0f6af6364..31bf056ac4 100644 --- a/packages/shared/src/components/modals/common.tsx +++ b/packages/shared/src/components/modals/common.tsx @@ -214,6 +214,13 @@ const AddToCustomFeedModal = dynamic( ), ); +const ReportUserModal = dynamic( + () => + import( + /* webpackChunkName: "reportUserModal" */ './report/ReportUserModal' + ), +); + export const modals = { [LazyModal.SquadMember]: SquadMemberModal, [LazyModal.UpvotedPopup]: UpvotedPopupModal, @@ -250,6 +257,7 @@ export const modals = { [LazyModal.ClickbaitShield]: ClickbaitShieldModal, [LazyModal.MoveBookmark]: MoveBookmarkModal, [LazyModal.AddToCustomFeed]: AddToCustomFeedModal, + [LazyModal.ReportUser]: ReportUserModal, }; type GetComponentProps = T extends diff --git a/packages/shared/src/components/modals/common/types.ts b/packages/shared/src/components/modals/common/types.ts index 00832f1e0b..64a3b9ff5e 100644 --- a/packages/shared/src/components/modals/common/types.ts +++ b/packages/shared/src/components/modals/common/types.ts @@ -60,6 +60,7 @@ export enum LazyModal { ClickbaitShield = 'clickbaitShield', MoveBookmark = 'moveBookmark', AddToCustomFeed = 'addToCustomFeed', + ReportUser = 'reportUser', } export type ModalTabItem = { diff --git a/packages/shared/src/components/modals/report/ReportUserModal.tsx b/packages/shared/src/components/modals/report/ReportUserModal.tsx new file mode 100644 index 0000000000..2caa1a5577 --- /dev/null +++ b/packages/shared/src/components/modals/report/ReportUserModal.tsx @@ -0,0 +1,122 @@ +import type { ReactElement } from 'react'; +import React, { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { ReasonSelectionModal } from './ReasonSelectionModal'; +import type { ReportReason } from '../../../report'; +import { ReportEntity, SEND_REPORT_MUTATION } from '../../../report'; +import { Checkbox } from '../../fields/Checkbox'; +import type { UserShortProfile } from '../../../lib/user'; +import { gqlClient } from '../../../graphql/common'; +import { + CONTENT_PREFERENCE_BLOCK_MUTATION, + ContentPreferenceType, +} from '../../../graphql/contentPreference'; +import { useAuthContext } from '../../../contexts/AuthContext'; +import { useToastNotification } from '../../../hooks'; +import { useLazyModal } from '../../../hooks/useLazyModal'; + +const reportReasons: { value: string; label: string }[] = [ + { value: 'INAPPROPRIATE', label: 'Inappropriate or NSFW content' }, + { value: 'TROLLING', label: 'Trolling or disruptive behavior' }, + { value: 'HARASSMENT', label: 'Harassment or bullying' }, + { value: 'IMPERSONATION', label: 'Impersonation or false identity' }, + { value: 'SPAM', label: 'Spam or unsolicited advertising' }, + { value: 'MISINFORMATION', label: 'Misinformation or false claims' }, + { value: 'HATEFUL', label: 'Hate speech or discrimination' }, + { value: 'PRIVACY', label: 'Privacy or copyright violation' }, + { value: 'PLAGIARISM', label: 'Plagiarism or content theft' }, + { value: 'OTHER', label: 'Other' }, +]; + +type ReportUserModalProps = { + defaultBlockUser?: boolean; + feedId?: string; + offendingUser: Pick; + onBlockUser?: () => void; +}; + +export const ReportUserModal = ({ + offendingUser, + defaultBlockUser, + feedId, + onBlockUser, +}: ReportUserModalProps): ReactElement => { + const { closeModal: onClose } = useLazyModal(); + const { displayToast } = useToastNotification(); + const { user } = useAuthContext(); + const [blockUser, setBlockUser] = useState(defaultBlockUser); + const { isPending: isBlockPending, mutateAsync: blockUserMutation } = + useMutation({ + mutationFn: () => + gqlClient.request(CONTENT_PREFERENCE_BLOCK_MUTATION, { + id: offendingUser.id, + entity: ContentPreferenceType.User, + feedId: feedId ?? user?.id, + }), + onSuccess: () => { + displayToast(`🚫 ${offendingUser.username} has been blocked`); + onBlockUser?.(); + }, + onError: () => { + displayToast(`❌ Failed to block ${offendingUser.username}`); + }, + onSettled: () => onClose(), + }); + const { isPending: isReportPending, mutateAsync: reportUserMutation } = + useMutation({ + mutationFn: ({ reason, text }: { reason: ReportReason; text: string }) => + gqlClient.request(SEND_REPORT_MUTATION, { + id: offendingUser.id, + type: ReportEntity.User, + reason, + comment: text, + }), + onSuccess: () => { + if (!blockUser) { + displayToast(`🗒️ ${offendingUser.username} has been reported`); + } + }, + onError: () => { + displayToast(`❌ Failed to report ${offendingUser.username}`); + }, + onSettled: () => onClose(), + }); + + const onReportUser = ( + e: React.MouseEvent, + reason: ReportReason, + text: string, + ) => { + e.preventDefault(); + reportUserMutation({ reason, text }); + if (blockUser) { + blockUserMutation(); + } + }; + + const isPending = isBlockPending || isReportPending; + const checkboxDisabled = defaultBlockUser || isPending; + return ( + setBlockUser(e.target.checked)} + checked={blockUser} + > + Block {offendingUser.username} + + } + /> + ); +}; + +export default ReportUserModal; diff --git a/packages/shared/src/components/profile/Header.tsx b/packages/shared/src/components/profile/Header.tsx index b165f147c5..8c54b48be9 100644 --- a/packages/shared/src/components/profile/Header.tsx +++ b/packages/shared/src/components/profile/Header.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import classNames from 'classnames'; import { useRouter } from 'next/router'; import type { PublicProfile } from '../../lib/user'; -import { SettingsIcon } from '../icons'; +import { BlockIcon, FlagIcon, SettingsIcon } from '../icons'; import { Button, ButtonSize, ButtonVariant } from '../buttons/Button'; import { ProfileImageSize, ProfilePicture } from '../ProfilePicture'; import { largeNumberFormat, ReferralCampaignKey } from '../../lib'; @@ -12,13 +12,19 @@ import { RootPortal } from '../tooltips/Portal'; import { GoBackButton } from '../post/GoBackHeaderMobile'; import { useViewSize, ViewSize } from '../../hooks'; import { FollowButton } from '../contentPreference/FollowButton'; -import { ContentPreferenceType } from '../../graphql/contentPreference'; +import { + ContentPreferenceStatus, + ContentPreferenceType, +} from '../../graphql/contentPreference'; import { UpgradeToPlus } from '../UpgradeToPlus'; import { useContentPreferenceStatusQuery } from '../../hooks/contentPreference/useContentPreferenceStatusQuery'; import { usePlusSubscription } from '../../hooks/usePlusSubscription'; import { LogEvent, TargetId } from '../../lib/log'; import CustomFeedOptionsMenu from '../CustomFeedOptionsMenu'; import { useContentPreference } from '../../hooks/contentPreference/useContentPreference'; +import { useLazyModal } from '../../hooks/useLazyModal'; +import { LazyModal } from '../modals/common/types'; +import { MenuIcon } from '../MenuIcon'; export interface HeaderProps { user: PublicProfile; @@ -36,6 +42,7 @@ export function Header({ className, style, }: HeaderProps): ReactElement { + const { openModal } = useLazyModal(); const isMobile = useViewSize(ViewSize.MobileL); const [isMenuOpen, setIsMenuOpen] = useState(false); const { isPlus } = usePlusSubscription(); @@ -45,6 +52,26 @@ export function Header({ id: user?.id, entity: ContentPreferenceType.User, }); + const { unblock, block } = useContentPreference(); + + const onReportUser = React.useCallback( + (defaultBlocked = false) => { + openModal({ + type: LazyModal.ReportUser, + props: { + offendingUser: { + id: user.id, + username: user.username, + }, + defaultBlockUser: defaultBlocked, + }, + }); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [user], + ); + + const blocked = contentPreference?.status === ContentPreferenceStatus.Blocked; return (
)} - + {!blocked && ( + + )} {!isSameUser && ( @@ -131,6 +160,29 @@ export function Header({ target_id: user.id, }), }} + additionalOptions={[ + { + icon: , + label: `${blocked ? 'Unblock' : 'Block'} ${user.username}`, + action: () => + blocked + ? unblock({ + id: user.id, + entity: ContentPreferenceType.User, + entityName: user.username, + }) + : block({ + id: user.id, + entity: ContentPreferenceType.User, + entityName: user.username, + }), + }, + { + icon: , + label: 'Report', + action: () => onReportUser(), + }, + ]} /> )}
diff --git a/packages/shared/src/components/profile/SourceList.tsx b/packages/shared/src/components/profile/SourceList.tsx index 9420ff49fc..2f7e13a491 100644 --- a/packages/shared/src/components/profile/SourceList.tsx +++ b/packages/shared/src/components/profile/SourceList.tsx @@ -20,6 +20,7 @@ import { SourceListPlaceholder } from './SourceListPlaceholder'; import { webappUrl } from '../../lib/constants'; import Link from '../utilities/Link'; import { anchorDefaultRel } from '../../lib/strings'; +import BlockButton from '../contentPreference/BlockButton'; export interface SourceListProps { scrollingProps: Omit; @@ -27,6 +28,8 @@ export interface SourceListProps { placeholderAmount?: number; isLoading?: boolean; emptyPlaceholder?: JSX.Element; + showFollow?: boolean; + showBlock?: boolean; } export const SourceList = ({ @@ -35,6 +38,8 @@ export const SourceList = ({ sources, isLoading, emptyPlaceholder, + showFollow = true, + showBlock, }: SourceListProps): ReactElement => { const feedSettingsEditContext = useFeedSettingsEditContext(); const feed = feedSettingsEditContext?.feed; @@ -50,63 +55,78 @@ export const SourceList = ({ placeholder={loader} > {sources.map((source) => ( - - - -
- - {source.name} - - - {source.handle} - {source.type === SourceType.Squad && ( - <> - - - Squad - - - )} - - - {source.description} - -
+ + +
+ + {source.name} + + + {source.handle} + {source.type === SourceType.Squad && ( + <> + + + Squad + + + )} + + + {source.description} + +
+ {showBlock && ( + + )} + {showFollow && ( -
- + )} + ))} ); diff --git a/packages/shared/src/components/profile/TagList.tsx b/packages/shared/src/components/profile/TagList.tsx index 4de97d1d76..1b33baac6c 100644 --- a/packages/shared/src/components/profile/TagList.tsx +++ b/packages/shared/src/components/profile/TagList.tsx @@ -13,6 +13,7 @@ import { FollowButton } from '../contentPreference/FollowButton'; import { useFeedSettingsEditContext } from '../feeds/FeedSettings/FeedSettingsEditContext'; import { CopyType } from '../sources/SourceActions/SourceActionsFollow'; import { TagListPlaceholder } from './TagListPlaceholder'; +import BlockButton from '../contentPreference/BlockButton'; export interface TagListProps { scrollingProps: Omit; @@ -20,6 +21,8 @@ export interface TagListProps { placeholderAmount?: number; isLoading?: boolean; emptyPlaceholder?: JSX.Element; + showBlock?: boolean; + showFollow?: boolean; } export const TagList = ({ @@ -28,6 +31,8 @@ export const TagList = ({ tags, isLoading, emptyPlaceholder, + showBlock = false, + showFollow = true, }: TagListProps): ReactElement => { const feedSettingsEditContext = useFeedSettingsEditContext(); const feed = feedSettingsEditContext?.feed; @@ -51,15 +56,26 @@ export const TagList = ({ > #{tag.referenceId} - + {showBlock && ( + + )} + {showFollow && ( + + )} ))} diff --git a/packages/shared/src/components/profile/UserList.tsx b/packages/shared/src/components/profile/UserList.tsx index 28478226ec..3a3f7df450 100644 --- a/packages/shared/src/components/profile/UserList.tsx +++ b/packages/shared/src/components/profile/UserList.tsx @@ -7,6 +7,7 @@ import { UserShortInfo } from './UserShortInfo'; import type { InfiniteScrollingProps } from '../containers/InfiniteScrolling'; import InfiniteScrolling from '../containers/InfiniteScrolling'; import type { UserShortProfile } from '../../lib/user'; +import { anchorDefaultRel } from '../../lib/strings'; export interface UserListProps { scrollingProps: Omit; @@ -48,17 +49,28 @@ function UserList({ > {!!initialItem && initialItem} {users.map((user, i) => ( - + ))} ); diff --git a/packages/shared/src/components/squads/SquadCommentJoinBanner.tsx b/packages/shared/src/components/squads/SquadCommentJoinBanner.tsx index 88e5f65a52..1cf4c7956b 100644 --- a/packages/shared/src/components/squads/SquadCommentJoinBanner.tsx +++ b/packages/shared/src/components/squads/SquadCommentJoinBanner.tsx @@ -14,6 +14,7 @@ import SourceButton from '../cards/common/SourceButton'; import { SQUAD_COMMENT_JOIN_BANNER_KEY } from '../../graphql/squads'; import type { Post } from '../../graphql/posts'; import { ProfileImageSize } from '../ProfilePicture'; +import { invalidatePostCacheById } from '../../hooks/usePostById'; export type SquadCommentJoinBannerProps = { className?: string; @@ -44,9 +45,7 @@ export const SquadCommentJoinBanner = ({ displayToast(`🙌 You joined the Squad ${squad.name}`); setIsSquadMember(true); if (post?.id) { - queryClient.invalidateQueries({ - queryKey: ['post', post.id], - }); + invalidatePostCacheById(queryClient, post.id); } }, onError: () => { diff --git a/packages/shared/src/contexts/PaymentContext.tsx b/packages/shared/src/contexts/PaymentContext.tsx index 72fe61851d..980534b413 100644 --- a/packages/shared/src/contexts/PaymentContext.tsx +++ b/packages/shared/src/contexts/PaymentContext.tsx @@ -28,6 +28,7 @@ export type ProductOption = { label: string; value: string; price: string; + priceUnformatted: number; currencyCode: string; extraLabel: string; }; @@ -165,6 +166,7 @@ export const PaymentContextProvider = ({ label: item.price.description, value: item.price.id, price: item.formattedTotals.total, + priceUnformatted: Number(item.totals.total), currencyCode: productPrices?.data.currencyCode as string, extraLabel: item.price.customData?.label as string, })) ?? [], @@ -182,7 +184,7 @@ export const PaymentContextProvider = ({ } return monthlyPrices.reduce((acc, plan) => { - return acc.price < plan.price ? acc : plan; + return acc.priceUnformatted < plan.priceUnformatted ? acc : plan; }).value; }, [planTypes, productOptions]); diff --git a/packages/shared/src/graphql/contentPreference.ts b/packages/shared/src/graphql/contentPreference.ts index f9e20ea33e..ae3f81b3f8 100644 --- a/packages/shared/src/graphql/contentPreference.ts +++ b/packages/shared/src/graphql/contentPreference.ts @@ -16,6 +16,7 @@ export enum ContentPreferenceType { export enum ContentPreferenceStatus { Follow = 'follow', Subscribed = 'subscribed', + Blocked = 'blocked', } type ContentPreferenceUser = Pick< diff --git a/packages/shared/src/graphql/fragments.ts b/packages/shared/src/graphql/fragments.ts index 8bc1db5754..5f66d4319b 100644 --- a/packages/shared/src/graphql/fragments.ts +++ b/packages/shared/src/graphql/fragments.ts @@ -197,6 +197,9 @@ export const FEED_POST_INFO_FRAGMENT = gql` image username permalink + contentPreference { + status + } } type tags diff --git a/packages/shared/src/hooks/contentPreference/types.ts b/packages/shared/src/hooks/contentPreference/types.ts index f7f52c59de..8df23c829e 100644 --- a/packages/shared/src/hooks/contentPreference/types.ts +++ b/packages/shared/src/hooks/contentPreference/types.ts @@ -20,6 +20,7 @@ export type ContentPreferenceMutation = ({ feedId?: string; opts?: Partial<{ extra: Record; + hideToast: boolean; }>; }) => Promise; @@ -38,6 +39,7 @@ export const contentPreferenceMutationMatcher: UseMutationMatcher< RequestKey.ContentPreferenceSubscribe, RequestKey.ContentPreferenceUnsubscribe, RequestKey.ContentPreferenceUnblock, + RequestKey.ContentPreferenceBlock, ].includes(requestKey as RequestKey) ); }; @@ -50,6 +52,7 @@ export const mutationKeyToContentPreferenceStatusMap: Partial< [RequestKey.ContentPreferenceSubscribe]: ContentPreferenceStatus.Subscribed, [RequestKey.ContentPreferenceUnsubscribe]: ContentPreferenceStatus.Follow, [RequestKey.ContentPreferenceUnblock]: null, + [RequestKey.ContentPreferenceBlock]: ContentPreferenceStatus.Blocked, }; export const isFollowingContent = ( diff --git a/packages/shared/src/hooks/contentPreference/useContentPreference.ts b/packages/shared/src/hooks/contentPreference/useContentPreference.ts index ee91c903df..44a9206a43 100644 --- a/packages/shared/src/hooks/contentPreference/useContentPreference.ts +++ b/packages/shared/src/hooks/contentPreference/useContentPreference.ts @@ -5,6 +5,7 @@ import { CONTENT_PREFERENCE_UNBLOCK_MUTATION, CONTENT_PREFERENCE_UNFOLLOW_MUTATION, ContentPreferenceStatus, + ContentPreferenceType, } from '../../graphql/contentPreference'; import { useAuthContext } from '../../contexts/AuthContext'; import { gqlClient } from '../../graphql/common'; @@ -220,7 +221,15 @@ export const useContentPreference = ({ feedId, }); - displayToast(`⛔️ You blocked the following ${entityName}: ${id}`); + if (opts?.hideToast) { + return; + } + + if (entity === ContentPreferenceType.User) { + displayToast(`🚫 ${entityName} has been blocked`); + } else { + displayToast(`⛔️ You blocked the following ${entityName}: ${id}`); + } }, }); diff --git a/packages/shared/src/hooks/notifications/useEnableNotification.ts b/packages/shared/src/hooks/notifications/useEnableNotification.ts index de3e247547..d995ef7eb6 100644 --- a/packages/shared/src/hooks/notifications/useEnableNotification.ts +++ b/packages/shared/src/hooks/notifications/useEnableNotification.ts @@ -51,14 +51,14 @@ export const useEnableNotification = ({ const conditions = [ isLoaded, !subscribed, - !isDismissed, isInitialized, isPushSupported || isExtension, ]; const shouldShowCta = - conditions.every(Boolean) || - (enabledJustNow && source !== NotificationPromptSource.SquadPostModal); + (conditions.every(Boolean) || + (enabledJustNow && source !== NotificationPromptSource.SquadPostModal)) && + !isDismissed; useEffect(() => { if (!shouldShowCta) { diff --git a/packages/shared/src/hooks/usePostById.ts b/packages/shared/src/hooks/usePostById.ts index fc79efe755..25e760f48b 100644 --- a/packages/shared/src/hooks/usePostById.ts +++ b/packages/shared/src/hooks/usePostById.ts @@ -40,6 +40,17 @@ export const POST_KEY = 'post'; export const getPostByIdKey = (id: string): QueryKey => [POST_KEY, id]; +export const invalidatePostCacheById = ( + client: QueryClient, + id: string, +): void => { + const postQueryKey = getPostByIdKey(id); + const postCache = client.getQueryData(postQueryKey); + if (postCache) { + client.invalidateQueries({ queryKey: postQueryKey }); + } +}; + export const updatePostCache = ( client: QueryClient, id: string, diff --git a/packages/shared/src/report.ts b/packages/shared/src/report.ts index e9cb1c23ac..2d89c4db00 100644 --- a/packages/shared/src/report.ts +++ b/packages/shared/src/report.ts @@ -6,6 +6,7 @@ export enum ReportEntity { Post = 'post', Source = 'source', Comment = 'comment', + User = 'user', } export enum ReportReason {