From 64a4e7369b7376319bc23639660980ea9185ee72 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Thu, 11 Jul 2024 23:31:45 +0700 Subject: [PATCH 01/26] Add approve message --- src/components/chats/UnapprovedMemeCount.tsx | 15 +++- .../extensions/common/CommonChatItem.tsx | 72 +++++++++++++++---- .../layouts/LayoutWithBottomNavigation.tsx | 3 +- src/pages/api/datahub/post.ts | 10 ++- src/server/datahub-queue/generated.ts | 8 +-- src/server/datahub-queue/post.ts | 41 +++++++++-- src/services/datahub/generated-query.ts | 12 +++- src/services/datahub/posts/mutation.ts | 20 ++++++ src/services/datahub/posts/query.ts | 16 ++++- 9 files changed, 164 insertions(+), 33 deletions(-) diff --git a/src/components/chats/UnapprovedMemeCount.tsx b/src/components/chats/UnapprovedMemeCount.tsx index 19954a46f..b21bb3e60 100644 --- a/src/components/chats/UnapprovedMemeCount.tsx +++ b/src/components/chats/UnapprovedMemeCount.tsx @@ -1,11 +1,14 @@ import { getUnapprovedMemesCountQuery } from '@/services/datahub/posts/query' +import { cx } from '@/utils/class-names' export default function UnapprovedMemeCount({ address, chatId, + className, }: { address: string chatId: string + className?: string }) { const { data: count, isLoading } = getUnapprovedMemesCountQuery.useQuery({ address, @@ -13,9 +16,17 @@ export default function UnapprovedMemeCount({ }) if (isLoading) return null + const approved = count?.approved ?? 0 + const unapproved = count?.unapproved ?? 0 + return ( -
- {(count ?? 0) >= 3 ? '✅' : '🚫'} {count ?? 0} +
+ {`⏳ ${unapproved} / ✅ ${approved}`}
) } diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 601b52094..89c94b788 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -74,7 +74,9 @@ export default function CommonChatItem({ showApproveButton, dummySuperLike, }: CommonChatItemProps) { - const { inView, ref } = useInView() + const { inView, ref } = useInView({ + triggerOnce: true, + }) const myAddress = useMyMainAddress() const { isAuthorized } = useAuthorizedForModeration(chatId) const { mutate: moderate, isLoading: loadingModeration } = @@ -190,6 +192,15 @@ export default function CommonChatItem({ )}
)} + + {showApproveButton && inView && ( + + )} +
- {showApproveButton && inView && ( - - )} {/* */} {othersMessage.checkMark === 'top' && otherMessageCheckMarkElement()} @@ -293,7 +301,7 @@ export default function CommonChatItem({
{showApproveButton && ( - + <> + + + )}
)} @@ -363,7 +377,7 @@ export default function CommonChatItem({ ) } -function ApproveButton({ +function ApproveUserButton({ ownerId, chatId, }: { @@ -374,7 +388,8 @@ function ApproveButton({ return ( ) } + +function ApproveMemeButton({ + messageId, + chatId, +}: { + chatId: string + messageId: string +}) { + // TODO: change + const { mutate, isLoading } = useApproveUser() + return ( + + ) +} diff --git a/src/components/layouts/LayoutWithBottomNavigation.tsx b/src/components/layouts/LayoutWithBottomNavigation.tsx index b045a7b0e..0a45fd53b 100644 --- a/src/components/layouts/LayoutWithBottomNavigation.tsx +++ b/src/components/layouts/LayoutWithBottomNavigation.tsx @@ -1,4 +1,3 @@ -import useRedirectToTgBotOnDesktop from '@/hooks/useRedirectToTgBotOnDesktop' import { cx } from '@/utils/class-names' import { ComponentProps } from 'react' import useLoginInTelegramMiniApps from '../navbar/Navbar/telegramLogin/useLoginInTelegramMiniApps' @@ -17,7 +16,7 @@ export default function LayoutWithBottomNavigation({ ...props }: DefaultLayoutProps) { useLoginInTelegramMiniApps() - useRedirectToTgBotOnDesktop() + // useRedirectToTgBotOnDesktop() return (
@@ -108,6 +114,8 @@ function datahubPostActionMapping(data: ApiDatahubPostMutationBody) { return updatePostData(data.payload) case 'approve-user': return approveUser(data.payload) + case 'approve-message': + return approveMessage(data.payload) default: throw new Error('Unknown action') } diff --git a/src/server/datahub-queue/generated.ts b/src/server/datahub-queue/generated.ts index d2b6db69b..26b67684c 100644 --- a/src/server/datahub-queue/generated.ts +++ b/src/server/datahub-queue/generated.ts @@ -579,11 +579,11 @@ export type UpdatePostOptimisticMutationVariables = Exact<{ export type UpdatePostOptimisticMutation = { __typename?: 'Mutation', updatePostOptimistic: { __typename?: 'IngestDataResponseDto', processed: boolean, callId?: string | null, message?: string | null } }; export type ApproveUserMutationVariables = Exact<{ - input: UpdatePostOptimisticInput; + input: SocialProfileAddReferrerIdInput; }>; -export type ApproveUserMutation = { __typename?: 'Mutation', updatePostOptimistic: { __typename?: 'IngestDataResponseDto', processed: boolean, callId?: string | null, message?: string | null } }; +export type ApproveUserMutation = { __typename?: 'Mutation', socialProfileSetActionPermissions: { __typename?: 'IngestDataResponseDto', processed: boolean, callId?: string | null, message?: string | null } }; export type SetReferrerIdMutationVariables = Exact<{ setReferrerIdInput: SocialProfileAddReferrerIdInput; @@ -719,8 +719,8 @@ export const UpdatePostOptimistic = gql` } `; export const ApproveUser = gql` - mutation ApproveUser($input: UpdatePostOptimisticInput!) { - updatePostOptimistic(updatePostOptimisticInput: $input) { + mutation ApproveUser($input: SocialProfileAddReferrerIdInput!) { + socialProfileSetActionPermissions(args: $input) { processed callId message diff --git a/src/server/datahub-queue/post.ts b/src/server/datahub-queue/post.ts index 9680b9799..4fc972fae 100644 --- a/src/server/datahub-queue/post.ts +++ b/src/server/datahub-queue/post.ts @@ -8,6 +8,7 @@ import { CreatePostOffChainMutationVariables, GetCanAccountDoQuery, GetCanAccountDoQueryVariables, + SocialProfileAddReferrerIdInput, UpdatePostOptimisticInput, UpdatePostOptimisticMutation, UpdatePostOptimisticMutationVariables, @@ -87,15 +88,15 @@ export async function updatePostData(input: UpdatePostOptimisticInput) { } const APPROVE_USER_MUTATION = gql` - mutation ApproveUser($input: UpdatePostOptimisticInput!) { - updatePostOptimistic(updatePostOptimisticInput: $input) { + mutation ApproveUser($input: SocialProfileAddReferrerIdInput!) { + socialProfileSetActionPermissions(args: $input) { processed callId message } } ` -export async function approveUser(input: UpdatePostOptimisticInput) { +export async function approveUser(input: SocialProfileAddReferrerIdInput) { const res = await datahubQueueRequest< ApproveUserMutation, ApproveUserMutationVariables @@ -105,6 +106,36 @@ export async function approveUser(input: UpdatePostOptimisticInput) { input, }, }) - throwErrorIfNotProcessed(res.updatePostOptimistic, 'Failed to approve user') - return res.updatePostOptimistic.callId + throwErrorIfNotProcessed( + res.socialProfileSetActionPermissions, + 'Failed to approve user' + ) + return res.socialProfileSetActionPermissions.callId +} + +// TODO: change +const APPROVE_MESSAGE_MUTATION = gql` + mutation ApproveMessage($input: SocialProfileAddReferrerIdInput!) { + socialProfileSetActionPermissions(args: $input) { + processed + callId + message + } + } +` +export async function approveMessage(input: SocialProfileAddReferrerIdInput) { + const res = await datahubQueueRequest< + ApproveUserMutation, + ApproveUserMutationVariables + >({ + document: APPROVE_MESSAGE_MUTATION, + variables: { + input, + }, + }) + throwErrorIfNotProcessed( + res.socialProfileSetActionPermissions, + 'Failed to approve message' + ) + return res.socialProfileSetActionPermissions.callId } diff --git a/src/services/datahub/generated-query.ts b/src/services/datahub/generated-query.ts index 2f3347afd..98262455c 100644 --- a/src/services/datahub/generated-query.ts +++ b/src/services/datahub/generated-query.ts @@ -2858,7 +2858,10 @@ export type GetUnapprovedMemesCountQueryVariables = Exact<{ export type GetUnapprovedMemesCountQuery = { __typename?: 'Query' - posts: { __typename?: 'FindPostsResponseDto'; total?: number | null } + posts: { + __typename?: 'FindPostsResponseDto' + data: Array<{ __typename?: 'Post'; approvedInRootPost: boolean }> + } } export type SubscribePostSubscriptionVariables = Exact<{ [key: string]: never }> @@ -3629,13 +3632,16 @@ export const GetUnapprovedMemesCount = gql` posts( args: { filter: { + createdAtTimeGt: "2024-07-10T16:17:49.243Z" createdByAccountAddress: $address - approvedInRootPost: false rootPostId: $postId } + pageSize: 100 } ) { - total + data { + approvedInRootPost + } } } ` diff --git a/src/services/datahub/posts/mutation.ts b/src/services/datahub/posts/mutation.ts index e935c2ecb..6f54d4824 100644 --- a/src/services/datahub/posts/mutation.ts +++ b/src/services/datahub/posts/mutation.ts @@ -317,3 +317,23 @@ async function approveUser(args: ApproveUserArgs) { ) } export const useApproveUser = mutationWrapper(approveUser) + +// TODO: change +type ApproveMessageArgs = + SocialCallDataArgs<'synth_social_profile_set_action_permissions'> +async function approveMessage(args: ApproveMessageArgs) { + const input = await createSignedSocialDataEvent( + socialCallName.synth_social_profile_set_action_permissions, + { ...getCurrentWallet(), args }, + args + ) + + await apiInstance.post( + '/api/datahub/post', + { + action: 'approve-message', + payload: input as any, + } + ) +} +export const useApproveMessage = mutationWrapper(approveMessage) diff --git a/src/services/datahub/posts/query.ts b/src/services/datahub/posts/query.ts index 9375b4065..5e52e0292 100644 --- a/src/services/datahub/posts/query.ts +++ b/src/services/datahub/posts/query.ts @@ -536,18 +536,22 @@ export const getTimeLeftUntilCanPostQuery = createQuery({ }), }) +// TODO: change const GET_UNAPPROVED_MEMES_COUNT = gql` query GetUnapprovedMemesCount($address: String!, $postId: String!) { posts( args: { filter: { + createdAtTimeGt: "2024-07-10T16:17:49.243Z" createdByAccountAddress: $address - approvedInRootPost: false rootPostId: $postId } + pageSize: 100 } ) { - total + data { + approvedInRootPost + } } } ` @@ -561,7 +565,13 @@ export const getUnapprovedMemesCountQuery = createQuery({ document: GET_UNAPPROVED_MEMES_COUNT, variables: { address, postId: chatId }, }) - return res.posts.total ?? 0 + let unapproved = 0 + let approved = 0 + res.posts.data.forEach((post) => { + if (post.approvedInRootPost) approved++ + else unapproved++ + }) + return { unapproved, approved } }, defaultConfigGenerator: (params) => ({ enabled: !!params?.address && !!params.chatId, From 9eedfe0aed997910eec4de599eec6d18e1f94495 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 00:13:06 +0700 Subject: [PATCH 02/26] Finish approve meme --- .../extensions/common/CommonChatItem.tsx | 14 +++++------ .../layouts/LayoutWithBottomNavigation.tsx | 3 ++- src/server/datahub-queue/generated.ts | 23 +++++++++++++++++++ src/server/datahub-queue/post.ts | 15 ++++++------ src/services/datahub/posts/mutation.ts | 6 ++--- src/services/datahub/posts/query.ts | 1 - yarn.lock | 10 ++++---- 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 89c94b788..05f4a6889 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -14,7 +14,10 @@ import useAuthorizedForModeration from '@/hooks/useAuthorizedForModeration' import useIsMessageBlocked from '@/hooks/useIsMessageBlocked' import { getSuperLikeCountQuery } from '@/services/datahub/content-staking/query' import { getModerationReasonsQuery } from '@/services/datahub/moderation/query' -import { useApproveUser } from '@/services/datahub/posts/mutation' +import { + useApproveMessage, + useApproveUser, +} from '@/services/datahub/posts/mutation' import { isMessageSent } from '@/services/subsocial/commentIds/optimistic' import { useMyMainAddress } from '@/stores/my-account' import { cx } from '@/utils/class-names' @@ -414,8 +417,7 @@ function ApproveMemeButton({ chatId: string messageId: string }) { - // TODO: change - const { mutate, isLoading } = useApproveUser() + const { mutate, isLoading } = useApproveMessage() return (
diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 05f4a6889..9ee10418d 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -353,6 +353,7 @@ export default function CommonChatItem({ {dummySuperLike ? ( void panelClassName?: string + preventOnClickOpen?: boolean panelSize?: MenuListProps['size'] } export type FloatingMenusProps = Omit & diff --git a/src/components/floating/FloatingWrapper.tsx b/src/components/floating/FloatingWrapper.tsx index eb49ac60a..4346ae930 100644 --- a/src/components/floating/FloatingWrapper.tsx +++ b/src/components/floating/FloatingWrapper.tsx @@ -12,6 +12,7 @@ import { useClientPoint, useDismiss, useFloating, + useFocus, useHover, useInteractions, useTransitionStyles, @@ -41,6 +42,7 @@ export type FloatingWrapperProps = { allowedPlacements?: Placement[] useClickPointAsAnchor?: boolean mainAxisOffset?: number + preventOnClickOpen?: boolean } export default function FloatingWrapper({ @@ -52,6 +54,7 @@ export default function FloatingWrapper({ showOnHover, allowedPlacements, useClickPointAsAnchor, + preventOnClickOpen = false, mainAxisOffset = 0, }: FloatingWrapperProps) { const [openMenu, setOpenMenu] = useState(false) @@ -92,9 +95,15 @@ export default function FloatingWrapper({ const dismiss = useDismiss(context, { bubbles: false, }) + + const focus = useFocus(context, { + enabled: true, + }) + const { getReferenceProps, getFloatingProps } = useInteractions([ clientPoint, dismiss, + focus, hover, ]) const { isMounted } = useTransitionStyles(context, { @@ -103,15 +112,15 @@ export default function FloatingWrapper({ const toggleDisplay = (e?: MouseEvent) => { if (!open && e && useClickPointAsAnchor) { - clientClickX.current = e.clientX - clientClickY.current = e.clientY + clientClickX.current = e?.clientX || (e as any)?.touches[0].clientX + clientClickY.current = e?.clientY || (e as any)?.touches[0].clientY } + onOpenChange(!open, e) } - const closeMenu = () => onOpenChange(false) const onClick: MouseEventHandler = (e) => { - if (isTouchDevice()) toggleDisplay(e) + if (isTouchDevice()) preventOnClickOpen ? closeMenu() : toggleDisplay(e) else closeMenu() } diff --git a/src/hooks/useLongTouch.tsx b/src/hooks/useLongTouch.tsx new file mode 100644 index 000000000..710e55c25 --- /dev/null +++ b/src/hooks/useLongTouch.tsx @@ -0,0 +1,68 @@ +import { useHapticFeedbackRaw } from '@tma.js/sdk-react' +import { useCallback, useRef } from 'react' + +interface LongPressOptions { + shouldPreventDefault?: boolean + delay?: number +} + +const isTouchEvent = (event: Event): event is TouchEvent => { + return 'touches' in event +} + +const preventDefault = (event: Event) => { + if (!isTouchEvent(event)) return + + if (event.touches.length < 2 && event.preventDefault) { + event.preventDefault() + } +} +const useLongTouch = ( + onLongPress: (e: any) => void, + { shouldPreventDefault = true, delay = 300 }: LongPressOptions = {}, + animation?: { + startAnimation: () => void + endAnimation: () => void + } +) => { + const haptic = useHapticFeedbackRaw(true) + const { startAnimation, endAnimation } = animation || {} + + const timeout = useRef>() + const animationTimeout = useRef>() + const target = useRef() + + const start = useCallback( + (event: React.MouseEvent | React.TouchEvent) => { + if (shouldPreventDefault && event.target) { + preventDefault(event as any) + } + target.current = event.target + + animationTimeout.current = setTimeout(() => { + startAnimation?.() + }, 100) + + timeout.current = setTimeout(() => { + onLongPress(event) + haptic?.result?.impactOccurred('medium') + }, delay) + }, + [delay, haptic?.result, onLongPress, shouldPreventDefault, startAnimation] + ) + + const clearAndPreventClick = useCallback(() => { + timeout.current && clearTimeout(timeout.current) + animationTimeout.current && clearTimeout(animationTimeout.current) + // endAnimation?.() + }, []) + + return { + onTouchStart: (e: React.TouchEvent) => start(e), + onMouseLeave: (e: React.MouseEvent) => clearAndPreventClick(), + onTouchEnd: (e: React.TouchEvent) => clearAndPreventClick(), + onTouchMove: (e: React.TouchEvent) => clearAndPreventClick(), + } +} + +export default useLongTouch diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 40515b99b..d42468fd0 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -46,11 +46,11 @@ export type AppCommonProps = { } export default function App(props: AppProps) { - // useEffect(() => { - // import('eruda').then(({ default: eruda }) => { - // eruda.init() - // }) - // }, []) + useEffect(() => { + import('eruda').then(({ default: eruda }) => { + eruda.init() + }) + }, []) return ( Date: Fri, 12 Jul 2024 12:12:46 +0300 Subject: [PATCH 07/26] Remove eruda --- src/pages/_app.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index d42468fd0..40515b99b 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -46,11 +46,11 @@ export type AppCommonProps = { } export default function App(props: AppProps) { - useEffect(() => { - import('eruda').then(({ default: eruda }) => { - eruda.init() - }) - }, []) + // useEffect(() => { + // import('eruda').then(({ default: eruda }) => { + // eruda.init() + // }) + // }, []) return ( Date: Fri, 12 Jul 2024 18:52:33 +0700 Subject: [PATCH 08/26] Reduce padding --- src/components/chats/ChatRoom/ChatRoom.tsx | 2 +- src/modules/chat/HomePage/ChatContent.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/chats/ChatRoom/ChatRoom.tsx b/src/components/chats/ChatRoom/ChatRoom.tsx index 739d3d1ae..05b27e42c 100644 --- a/src/components/chats/ChatRoom/ChatRoom.tsx +++ b/src/components/chats/ChatRoom/ChatRoom.tsx @@ -101,7 +101,7 @@ function ChatInputWrapper({ return ( <> - +
setIsOpenRules(true)} > @@ -341,7 +341,7 @@ function PostMemeButton({ loadingEvmAddress } type='button' - className='flex items-center justify-center gap-2 px-0 disabled:border-none disabled:bg-background-light/30 disabled:text-text-muted/50 disabled:!brightness-100' + className='flex items-center justify-center gap-2 px-0 py-2.5 disabled:border-none disabled:bg-background-light/30 disabled:text-text-muted/50 disabled:!brightness-100' size='lg' variant={isMoreThanThreshold ? 'primary' : 'primaryOutline'} onClick={() => { From dcbfd421ab855b718a1595fad1e1906d05e66dbb Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 19:58:16 +0700 Subject: [PATCH 09/26] Add approve message in chat menu --- .../chats/ChatItem/ChatItemMenus.tsx | 28 ++++++++++- src/components/chats/UnapprovedUserChip.tsx | 14 ++++++ .../extensions/common/CommonChatItem.tsx | 11 +++-- src/services/datahub/events/subscription.tsx | 5 ++ src/services/datahub/generated-query.ts | 30 +++++++++++- src/services/datahub/identity/query.ts | 47 ++++++++++++++++++- 6 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 src/components/chats/UnapprovedUserChip.tsx diff --git a/src/components/chats/ChatItem/ChatItemMenus.tsx b/src/components/chats/ChatItem/ChatItemMenus.tsx index c85bbf1c9..9b8212503 100644 --- a/src/components/chats/ChatItem/ChatItemMenus.tsx +++ b/src/components/chats/ChatItem/ChatItemMenus.tsx @@ -17,8 +17,10 @@ import useIsOwnerOfPost from '@/hooks/useIsOwnerOfPost' import useRerender from '@/hooks/useRerender' import useToastError from '@/hooks/useToastError' import { getPostQuery } from '@/services/api/query' +import { getSocialProfileQuery } from '@/services/datahub/identity/query' import { useModerationActions } from '@/services/datahub/moderation/mutation' import { getModerationReasonsQuery } from '@/services/datahub/moderation/query' +import { useApproveUser } from '@/services/datahub/posts/mutation' import { usePinMessage } from '@/services/subsocial/posts/mutation' import { useSendEvent } from '@/stores/analytics' import { useChatMenu } from '@/stores/chat-menu' @@ -32,6 +34,7 @@ import { ImageProperties, PostData } from '@subsocial/api/types' import { SocialCallDataArgs } from '@subsocial/data-hub-sdk' import { useEffect, useState } from 'react' import { BsFillPinAngleFill } from 'react-icons/bs' +import { FaCheck } from 'react-icons/fa6' import { HiChevronRight, HiMiniArrowUturnLeft, @@ -73,7 +76,12 @@ export default function ChatItemMenus({ const { data: post } = getPostQuery.useQuery(messageId) const ownerId = post?.struct.ownerId ?? '' - const { ref } = useInView({ triggerOnce: true }) + const { ref, inView } = useInView({ triggerOnce: true }) + const { data: socialProfile, isLoading: loadingSocialProfile } = + getSocialProfileQuery.useQuery(ownerId, { + enabled: inView, + }) + const { mutate: approveUser } = useApproveUser() const { data: message } = getPostQuery.useQuery(messageId) const [modalState, setModalState] = useState(null) @@ -144,6 +152,22 @@ export default function ChatItemMenus({ }) }, }) + if ( + !loadingSocialProfile && + !socialProfile?.allowedCreateCommentRootPostIds.includes(chatId) + ) { + menus.unshift({ + text: 'Approve User', + icon: FaCheck, + onClick: () => { + sendEvent('approve_user', { hubId, chatId }) + approveUser({ + address: ownerId, + allow: { createCommentRootPostIds: [chatId] }, + }) + }, + }) + } } if (isOptimisticMessage) return menus @@ -259,7 +283,7 @@ export default function ChatItemMenus({ > {children} -
+
{message && ( ⏳ +} diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 9ee10418d..818620d0f 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -6,12 +6,14 @@ import ChatRelativeTime from '@/components/chats/ChatItem/ChatRelativeTime' import MessageStatusIndicator from '@/components/chats/ChatItem/MessageStatusIndicator' import RepliedMessagePreview from '@/components/chats/ChatItem/RepliedMessagePreview' import UnapprovedMemeCount from '@/components/chats/UnapprovedMemeCount' +import UnapprovedUserChip from '@/components/chats/UnapprovedUserChip' import { getRepliedMessageId } from '@/components/chats/utils' import SuperLike, { SuperLikeButton, } from '@/components/content-staking/SuperLike' import useAuthorizedForModeration from '@/hooks/useAuthorizedForModeration' import useIsMessageBlocked from '@/hooks/useIsMessageBlocked' +import useIsModerationAdmin from '@/hooks/useIsModerationAdmin' import { getSuperLikeCountQuery } from '@/services/datahub/content-staking/query' import { getModerationReasonsQuery } from '@/services/datahub/moderation/query' import { @@ -97,6 +99,7 @@ export default function CommonChatItem({ const relativeTime = getTimeRelativeToNow(createdAtTime) const isSent = isMessageSent(message.id, dataType) + const isAdmin = useIsModerationAdmin() const isMessageBlockedInCurrentHub = useIsMessageBlocked( hubId, message, @@ -172,7 +175,7 @@ export default function CommonChatItem({ className={cx( 'absolute bottom-1.5 right-1.5 z-10 flex items-center gap-1 self-end rounded-full px-1.5 py-0.5', (isMyMessageChildrenOnBottom || showApproveButton) && 'bg-black/45', - showApproveButton && 'bottom-16' + showApproveButton && 'bottom-14' )} > {myMessageCheckMarkElement( @@ -220,8 +223,7 @@ export default function CommonChatItem({ {!isMyMessage && (
@@ -238,6 +240,9 @@ export default function CommonChatItem({ className={cx('text-sm font-medium text-text-secondary')} /> {/* */} + {inView && isAdmin && ( + + )} {othersMessage.checkMark === 'top' && otherMessageCheckMarkElement()}
diff --git a/src/services/datahub/events/subscription.tsx b/src/services/datahub/events/subscription.tsx index f30e3fd02..c723a93c2 100644 --- a/src/services/datahub/events/subscription.tsx +++ b/src/services/datahub/events/subscription.tsx @@ -18,6 +18,7 @@ import { SubscribeEventsSubscription, SubscribeEventsSubscriptionVariables, } from '../generated-query' +import { getSocialProfileQuery } from '../identity/query' import { callIdToPostIdMap } from '../posts/mutation' import { getProfileQuery } from '../profiles/query' import { getGamificationTasksErrorQuery } from '../tasks/query' @@ -224,6 +225,10 @@ async function processSubscriptionEvent( }`} /> )) + getSocialProfileQuery.invalidate( + client, + eventData.meta.extension?.updatedCreatorAddress + ) return } diff --git a/src/services/datahub/generated-query.ts b/src/services/datahub/generated-query.ts index 98262455c..0d3227f4c 100644 --- a/src/services/datahub/generated-query.ts +++ b/src/services/datahub/generated-query.ts @@ -972,6 +972,7 @@ export type Post = { activeStakingSuperLikes?: Maybe> activeStakingSuperLikesCount?: Maybe approvedInRootPost: Scalars['Boolean']['output'] + approvedInRootPostAtTime?: Maybe /** is off-chain data CID backed up in blockchain */ backupInBlockchain?: Maybe blockchainSyncFailed: Scalars['Boolean']['output'] @@ -1555,6 +1556,7 @@ export enum SocialCallName { SynthModerationForceUnblockResource = 'synth_moderation_force_unblock_resource', SynthModerationInitModerator = 'synth_moderation_init_moderator', SynthModerationUnblockResource = 'synth_moderation_unblock_resource', + SynthSetPostApproveStatus = 'synth_set_post_approve_status', SynthSocialProfileAddReferrerId = 'synth_social_profile_add_referrer_id', SynthSocialProfileSetActionPermissions = 'synth_social_profile_set_action_permissions', SynthUpdatePostTxFailed = 'synth_update_post_tx_failed', @@ -2290,6 +2292,22 @@ export type GetLinkedIdentitiesFromProviderIdQuery = { } | null } +export type GetSocialProfileQueryVariables = Exact<{ + addresses: Array | Scalars['String']['input'] +}> + +export type GetSocialProfileQuery = { + __typename?: 'Query' + socialProfiles: { + __typename?: 'SocialProfilesResponse' + data: Array<{ + __typename?: 'SocialProfile' + id: string + allowedCreateCommentRootPostIds: Array + }> + } +} + export type SubscribeIdentitySubscriptionVariables = Exact<{ [key: string]: never }> @@ -3287,6 +3305,16 @@ export const GetLinkedIdentitiesFromProviderId = gql` } } ` +export const GetSocialProfile = gql` + query GetSocialProfile($addresses: [String!]!) { + socialProfiles(args: { where: { substrateAddresses: $addresses } }) { + data { + id + allowedCreateCommentRootPostIds + } + } + } +` export const SubscribeIdentity = gql` subscription SubscribeIdentity { linkedIdentitySubscription { @@ -3632,7 +3660,7 @@ export const GetUnapprovedMemesCount = gql` posts( args: { filter: { - createdAtTimeGt: "2024-07-10T16:17:49.243Z" + createdAtTimeGt: "2024-07-10T17:37:35.000Z" createdByAccountAddress: $address rootPostId: $postId } diff --git a/src/services/datahub/identity/query.ts b/src/services/datahub/identity/query.ts index 7d420f7c2..c722951d9 100644 --- a/src/services/datahub/identity/query.ts +++ b/src/services/datahub/identity/query.ts @@ -1,8 +1,14 @@ import { apiInstance } from '@/services/api/utils' import { useMyAccount } from '@/stores/my-account' -import { createQuery } from '@/subsocial-query' +import { createQuery, poolQuery } from '@/subsocial-query' import { LocalStorage } from '@/utils/storage' import { parseJSONData } from '@/utils/strings' +import { gql } from 'graphql-request' +import { + GetSocialProfileQuery, + GetSocialProfileQueryVariables, +} from '../generated-query' +import { datahubQueryRequest } from '../utils' import { getLinkedIdentity } from './fetcher' // NOTE: need to be careful when changing the structure of these cached data, because it can cause the app to crash if you access unavailable data @@ -53,3 +59,42 @@ export const getEvmLinkedIdentityMessageQuery = createQuery({ retry: false, }), }) + +const GET_SOCIAL_PROFILE = gql` + query GetSocialProfile($addresses: [String!]!) { + socialProfiles(args: { where: { substrateAddresses: $addresses } }) { + data { + id + allowedCreateCommentRootPostIds + } + } + } +` +const getSocialProfile = poolQuery< + string, + { id: string; allowedCreateCommentRootPostIds: string[] } +>({ + name: 'getSocialProfile', + multiCall: async (addresses) => { + const data = await datahubQueryRequest< + GetSocialProfileQuery, + GetSocialProfileQueryVariables + >({ + document: GET_SOCIAL_PROFILE, + variables: { addresses }, + }) + + return data.socialProfiles.data + }, + resultMapper: { + paramToKey: (address) => address, + resultToKey: (result) => result.id || '', + }, +}) +export const getSocialProfileQuery = createQuery({ + key: 'getSocialProfile', + fetcher: (address: string) => getSocialProfile(address), + defaultConfigGenerator: (data) => ({ + enabled: !!data, + }), +}) From 03d8412490d47d1fe33531d9bbecf6ca8e28f491 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 20:01:03 +0700 Subject: [PATCH 10/26] Only admin that fetches social profile query --- src/components/chats/ChatItem/ChatItemMenus.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/chats/ChatItem/ChatItemMenus.tsx b/src/components/chats/ChatItem/ChatItemMenus.tsx index 9b8212503..c20ce6f2c 100644 --- a/src/components/chats/ChatItem/ChatItemMenus.tsx +++ b/src/components/chats/ChatItem/ChatItemMenus.tsx @@ -13,6 +13,7 @@ import MetadataModal from '@/components/modals/MetadataModal' import ModerationModal from '@/components/moderation/ModerationModal' import { sendEventWithRef } from '@/components/referral/analytics' import useAuthorizedForModeration from '@/hooks/useAuthorizedForModeration' +import useIsModerationAdmin from '@/hooks/useIsModerationAdmin' import useIsOwnerOfPost from '@/hooks/useIsOwnerOfPost' import useRerender from '@/hooks/useRerender' import useToastError from '@/hooks/useToastError' @@ -77,9 +78,11 @@ export default function ChatItemMenus({ const { data: post } = getPostQuery.useQuery(messageId) const ownerId = post?.struct.ownerId ?? '' const { ref, inView } = useInView({ triggerOnce: true }) + + const isAdmin = useIsModerationAdmin() const { data: socialProfile, isLoading: loadingSocialProfile } = getSocialProfileQuery.useQuery(ownerId, { - enabled: inView, + enabled: inView && isAdmin, }) const { mutate: approveUser } = useApproveUser() From 96ef3bae29a352b3cf72dbd01133b6d3ed4d223d Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 20:35:12 +0700 Subject: [PATCH 11/26] Not show sandwatch emoji if in pendingtab --- src/components/extensions/common/CommonChatItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 818620d0f..0c1bc12eb 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -240,7 +240,7 @@ export default function CommonChatItem({ className={cx('text-sm font-medium text-text-secondary')} /> {/* */} - {inView && isAdmin && ( + {inView && isAdmin && !showApproveButton && ( )} {othersMessage.checkMark === 'top' && From 57bed44a708710ba0b1ce6c7e651c2eecae87d28 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 20:42:32 +0700 Subject: [PATCH 12/26] Finish swap order in pending tabs --- src/@types/subsocial.d.ts | 1 + src/services/datahub/generated-query.ts | 7 ++ src/services/datahub/mappers.ts | 1 + src/services/datahub/posts/fetcher.ts | 1 + src/services/datahub/posts/query.ts | 9 +- src/services/datahub/posts/subscription.tsx | 101 +++++++++++--------- 6 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/@types/subsocial.d.ts b/src/@types/subsocial.d.ts index e29dc63a6..8958c758f 100644 --- a/src/@types/subsocial.d.ts +++ b/src/@types/subsocial.d.ts @@ -102,6 +102,7 @@ declare module '@subsocial/api/types' { dataType?: 'persistent' | 'optimistic' | 'offChain' parentPostId?: string | null approvedInRootPost?: boolean + approvedInRootPostAtTime: string }, PostContent > & { requestedId?: string } diff --git a/src/services/datahub/generated-query.ts b/src/services/datahub/generated-query.ts index 0d3227f4c..d856244f5 100644 --- a/src/services/datahub/generated-query.ts +++ b/src/services/datahub/generated-query.ts @@ -2643,6 +2643,7 @@ export type DatahubPostFragmentFragment = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -2676,6 +2677,7 @@ export type GetPostsQuery = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -2710,6 +2712,7 @@ export type GetOptimisticPostsQuery = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -2743,6 +2746,7 @@ export type GetCommentIdsInPostIdQuery = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -2808,6 +2812,7 @@ export type GetOwnedPostsQuery = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -2840,6 +2845,7 @@ export type GetPostsBySpaceIdQuery = { title?: string | null body?: string | null approvedInRootPost: boolean + approvedInRootPostAtTime?: any | null createdByAccount: { __typename?: 'Account'; id: string } space?: { __typename?: 'Space'; id: string } | null ownedByAccount: { __typename?: 'Account'; id: string } @@ -3020,6 +3026,7 @@ export const DatahubPostFragment = gql` title body approvedInRootPost + approvedInRootPostAtTime ownedByAccount { id } diff --git a/src/services/datahub/mappers.ts b/src/services/datahub/mappers.ts index 5bda75898..93abb3d83 100644 --- a/src/services/datahub/mappers.ts +++ b/src/services/datahub/mappers.ts @@ -52,6 +52,7 @@ export const mapDatahubPostFragment = ( sharesCount: 0, spaceId: '', approvedInRootPost: post.approvedInRootPost ?? false, + approvedInRootPostAtTime: post.approvedInRootPostAtTime ?? '', isUpdated: false, rootPostId: post.rootPost?.persistentId ?? '', parentPostId: null, diff --git a/src/services/datahub/posts/fetcher.ts b/src/services/datahub/posts/fetcher.ts index ed882c778..2a0c97154 100644 --- a/src/services/datahub/posts/fetcher.ts +++ b/src/services/datahub/posts/fetcher.ts @@ -22,6 +22,7 @@ export const DATAHUB_POST_FRAGMENT = gql` title body approvedInRootPost + approvedInRootPostAtTime ownedByAccount { id } diff --git a/src/services/datahub/posts/query.ts b/src/services/datahub/posts/query.ts index c03c34422..d4f7355c5 100644 --- a/src/services/datahub/posts/query.ts +++ b/src/services/datahub/posts/query.ts @@ -112,7 +112,9 @@ async function getPaginatedPostIdsByRootPostId({ approvedInRootPost: !onlyDisplayUnapprovedMessages, }, orderBy: 'createdAtTime', - orderDirection: QueryOrder.Desc, + orderDirection: onlyDisplayUnapprovedMessages + ? QueryOrder.Asc + : QueryOrder.Desc, pageSize: CHAT_PER_PAGE, offset, }, @@ -232,6 +234,11 @@ export const getPaginatedPostIdsByPostId = { } }) }, + invalidateLastQuery: (client: QueryClient, data: Data) => { + client.invalidateQueries(getQueryKey(data), { + refetchPage: (_, index, allPages) => index === allPages.length - 1, + }) + }, invalidateFirstQuery: (client: QueryClient, data: Data) => { client.invalidateQueries(getQueryKey(data), { refetchPage: (_, index) => index === 0, diff --git a/src/services/datahub/posts/subscription.tsx b/src/services/datahub/posts/subscription.tsx index a88d6b708..f20af9714 100644 --- a/src/services/datahub/posts/subscription.tsx +++ b/src/services/datahub/posts/subscription.tsx @@ -213,7 +213,7 @@ async function processMessage( queryClient, { address: ownerId, chatId: rootPostId ?? '' } ) - if (typeof cachedCount === 'number') { + if (cachedCount) { getUnapprovedMemesCountQuery.setQueryData( queryClient, { address: ownerId, chatId: rootPostId ?? '' }, @@ -277,7 +277,8 @@ async function processMessage( if (!rootPostId) return - if (isCreationEvent && !entity.approvedInRootPost && isCurrentOwner) { + const isApproved = entity.approvedInRootPost + if (isCreationEvent && !isApproved && isCurrentOwner) { getPaginatedPostIdsByPostId.setQueryFirstPageData( queryClient, { @@ -309,58 +310,66 @@ async function processMessage( ) } - getPaginatedPostIdsByPostId.setQueryFirstPageData( - queryClient, - { - postId: rootPostId, - onlyDisplayUnapprovedMessages: !newPost?.struct.approvedInRootPost, - myAddress: getMyMainAddress() ?? '', - }, - (oldData) => { - if (!oldData) return [newestId] - const oldIdsSet = new Set(oldData) - if (oldIdsSet.has(newestId)) return oldData + if (isApproved) { + getPaginatedPostIdsByPostId.setQueryFirstPageData( + queryClient, + { + postId: rootPostId, + onlyDisplayUnapprovedMessages: !isApproved, + myAddress: getMyMainAddress() ?? '', + }, + (oldData) => { + if (!oldData) return [newestId] + const oldIdsSet = new Set(oldData) + if (oldIdsSet.has(newestId)) return oldData - const newIds = [...oldData] + const newIds = [...oldData] - const usedAsClientOptimisticId = entity.optimisticId || entity.id - const clientOptimisticId = commentIdsOptimisticEncoder.encode( - usedAsClientOptimisticId ?? '' - ) - if (oldIdsSet.has(clientOptimisticId)) { - const optimisticIdIndex = newIds.findIndex( - (id) => id === clientOptimisticId + const usedAsClientOptimisticId = entity.optimisticId || entity.id + const clientOptimisticId = commentIdsOptimisticEncoder.encode( + usedAsClientOptimisticId ?? '' ) - newIds.splice(optimisticIdIndex, 1, newestId) - return newIds - } + if (oldIdsSet.has(clientOptimisticId)) { + const optimisticIdIndex = newIds.findIndex( + (id) => id === clientOptimisticId + ) + newIds.splice(optimisticIdIndex, 1, newestId) + return newIds + } - if (entity.persistentId && oldIdsSet.has(entity.id)) { - const optimisticIdIndex = newIds.findIndex((id) => id === entity.id) - newIds.splice(optimisticIdIndex, 1, newestId) + if (entity.persistentId && oldIdsSet.has(entity.id)) { + const optimisticIdIndex = newIds.findIndex((id) => id === entity.id) + newIds.splice(optimisticIdIndex, 1, newestId) - return newIds - } + return newIds + } - const index = oldData.findIndex((id) => { - const data = getPostQuery.getQueryData(queryClient, id) - if (!data) return false - if ( - new Date(data.struct.createdAtTime) <= - new Date(eventData.entity.createdAtTime) - ) { - newIds.unshift(newestId) - return true + const index = oldData.findIndex((id) => { + const data = getPostQuery.getQueryData(queryClient, id) + if (!data) return false + if ( + new Date(data.struct.createdAtTime) <= + new Date(eventData.entity.createdAtTime) + ) { + newIds.unshift(newestId) + return true + } + return false + }) + if (index !== -1 || oldData.length <= 0) { + newIds.splice(index, 0, newestId) } - return false - }) - if (index !== -1 || oldData.length <= 0) { - newIds.splice(index, 0, newestId) - } - return newIds - } - ) + return newIds + } + ) + } else { + getPaginatedPostIdsByPostId.invalidateLastQuery(queryClient, { + postId: rootPostId, + onlyDisplayUnapprovedMessages: !isApproved, + myAddress: getMyMainAddress() ?? '', + }) + } getPostMetadataQuery.invalidate(queryClient, rootPostId) } From 2f92b7ef87e5f67b5f01f5e0f43a2784542e5cf4 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 22:49:27 +0700 Subject: [PATCH 13/26] Change order by for paginated post --- src/services/datahub/posts/query.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/datahub/posts/query.ts b/src/services/datahub/posts/query.ts index d4f7355c5..4742ed613 100644 --- a/src/services/datahub/posts/query.ts +++ b/src/services/datahub/posts/query.ts @@ -111,7 +111,9 @@ async function getPaginatedPostIdsByRootPostId({ rootPostId: postId, approvedInRootPost: !onlyDisplayUnapprovedMessages, }, - orderBy: 'createdAtTime', + orderBy: onlyDisplayUnapprovedMessages + ? 'createdAtTime' + : 'approvedInRootPostAtTime', orderDirection: onlyDisplayUnapprovedMessages ? QueryOrder.Asc : QueryOrder.Desc, From 04765a8d0415be2dd3ca98f60fb9beebeea643d7 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Fri, 12 Jul 2024 22:56:47 +0700 Subject: [PATCH 14/26] Change displayed time based on approval --- src/@types/subsocial.d.ts | 2 +- .../extensions/common/CommonChatItem.tsx | 15 ++++++++++++--- src/components/modals/LikeIntroModal.tsx | 2 ++ src/services/datahub/mappers.ts | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/@types/subsocial.d.ts b/src/@types/subsocial.d.ts index 8958c758f..44538fba2 100644 --- a/src/@types/subsocial.d.ts +++ b/src/@types/subsocial.d.ts @@ -102,7 +102,7 @@ declare module '@subsocial/api/types' { dataType?: 'persistent' | 'optimistic' | 'offChain' parentPostId?: string | null approvedInRootPost?: boolean - approvedInRootPostAtTime: string + approvedInRootPostAtTime: number }, PostContent > & { requestedId?: string } diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 0c1bc12eb..8e3e0268a 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -90,7 +90,13 @@ export default function CommonChatItem({ const firstReasonId = reasons?.[0].id const { struct, content } = message - const { ownerId, createdAtTime, dataType, isUpdated } = struct + const { + ownerId, + createdAtTime, + approvedInRootPostAtTime, + dataType, + isUpdated, + } = struct const { body } = content || {} const repliedMessageId = getRepliedMessageId(message) const { data: superLikeCount } = getSuperLikeCountQuery.useQuery(message.id) @@ -118,10 +124,13 @@ export default function CommonChatItem({ ? children({ isMyMessage, relativeTime, isSent }) : children + const displayedTime = showApproveButton + ? createdAtTime + : approvedInRootPostAtTime const otherMessageCheckMarkElement = (className?: string) => ( Date: Sat, 13 Jul 2024 01:30:35 +0700 Subject: [PATCH 15/26] Reset image upload after submit --- src/components/extensions/image/ImageModal.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/extensions/image/ImageModal.tsx b/src/components/extensions/image/ImageModal.tsx index 318acfc99..b3f74b9ca 100644 --- a/src/components/extensions/image/ImageModal.tsx +++ b/src/components/extensions/image/ImageModal.tsx @@ -77,7 +77,17 @@ export default function ImageModal({ return ( { + onSubmit() + setImageLinkStatus({ + isShowingImage: false, + loadedLink: null, + }) + setImageUploadStatus({ + isShowingImage: false, + loadedLink: null, + }) + }} extensionType='subsocial-image' description={ From 5a99d8bb9e1296ac217e4e8ef3893f5e42f7225e Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Sat, 13 Jul 2024 01:31:28 +0700 Subject: [PATCH 16/26] Fix wrong data used --- src/components/modals/MemeOnReviewModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/modals/MemeOnReviewModal.tsx b/src/components/modals/MemeOnReviewModal.tsx index 3df9c3902..7f7fdaa1d 100644 --- a/src/components/modals/MemeOnReviewModal.tsx +++ b/src/components/modals/MemeOnReviewModal.tsx @@ -32,7 +32,7 @@ export default function MemeOnReviewModal({ : `${ tokenomics?.socialActionPrice.createCommentPoints } points have been used. We received ${ - count ?? 0 + count?.unapproved ?? 0 } memes from you! Now we need a bit of time to finish review you as a verified creator.` return ( From f1253688ff88587b12a3f50c0052d1e0af1195ac Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Sat, 13 Jul 2024 01:33:18 +0700 Subject: [PATCH 17/26] Add approved time in optimistic post data --- src/services/subsocial/commentIds/optimistic.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/subsocial/commentIds/optimistic.ts b/src/services/subsocial/commentIds/optimistic.ts index 9718c380a..cb0ad099a 100644 --- a/src/services/subsocial/commentIds/optimistic.ts +++ b/src/services/subsocial/commentIds/optimistic.ts @@ -39,6 +39,7 @@ export function addOptimisticData({ id: newId, struct: { createdAtTime: Date.now(), + approvedInRootPostAtTime: Date.now(), ownerId: address, rootPostId: params.chatId, parentPostId: params.replyTo, From 74f890de852809cd5af56245c3221cc46a0dc982 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Jul 2024 14:20:13 +0300 Subject: [PATCH 18/26] Disable super like on double tap when contest ended --- src/components/chats/ChatItem/ChatItem.tsx | 7 ++++++- src/components/chats/ChatList/ChatItemWithMenu.tsx | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/chats/ChatItem/ChatItem.tsx b/src/components/chats/ChatItem/ChatItem.tsx index 9926ebc21..6ae666ac5 100644 --- a/src/components/chats/ChatItem/ChatItem.tsx +++ b/src/components/chats/ChatItem/ChatItem.tsx @@ -101,6 +101,7 @@ export default function ChatItem({ config={config} superLikeProps={props} messageBubbleId={messageBubbleId} + disableSuperLike={disableSuperLike} > {extensions && extensions.length > 0 ? ( { const containerRef = useRef(null) const { toggleDisplay, referenceProps } = config || {} @@ -240,7 +245,7 @@ const ChatItemMenuWrapper = ({ e.preventDefault() e.stopPropagation() - if (!isDisabled && !hasILiked) { + if (!isDisabled && !disableSuperLike && !hasILiked) { haptic?.result?.impactOccurred('medium') handleClick() animateHeart(e.clientX, e.clientY) diff --git a/src/components/chats/ChatList/ChatItemWithMenu.tsx b/src/components/chats/ChatList/ChatItemWithMenu.tsx index 8fb411e1c..fe8cf5c56 100644 --- a/src/components/chats/ChatList/ChatItemWithMenu.tsx +++ b/src/components/chats/ChatList/ChatItemWithMenu.tsx @@ -52,6 +52,7 @@ function InnerChatItemWithMenu({ message={message} showBlockedMessage={showBlockedMessage} messageBubbleId={getMessageElementId(message.id)} + disableSuperLike={disableSuperLike} enableProfileModal={enableProfileModal} scrollToMessage={scrollToMessage} showApproveButton={showApproveButton} From 5097c1037e18f5bda31ed05218623d0074d663b8 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Mon, 15 Jul 2024 20:21:43 +0700 Subject: [PATCH 19/26] Remove approve user button --- src/components/extensions/common/CommonChatItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 8e3e0268a..fdc38a308 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -318,7 +318,7 @@ export default function CommonChatItem({
) } diff --git a/src/services/datahub/generated-query.ts b/src/services/datahub/generated-query.ts index d856244f5..77593b71b 100644 --- a/src/services/datahub/generated-query.ts +++ b/src/services/datahub/generated-query.ts @@ -2884,7 +2884,11 @@ export type GetUnapprovedMemesCountQuery = { __typename?: 'Query' posts: { __typename?: 'FindPostsResponseDto' - data: Array<{ __typename?: 'Post'; approvedInRootPost: boolean }> + data: Array<{ + __typename?: 'Post' + id: string + approvedInRootPost: boolean + }> } } @@ -3675,6 +3679,7 @@ export const GetUnapprovedMemesCount = gql` } ) { data { + id approvedInRootPost } } diff --git a/src/services/datahub/posts/query.ts b/src/services/datahub/posts/query.ts index 4742ed613..b35a2e003 100644 --- a/src/services/datahub/posts/query.ts +++ b/src/services/datahub/posts/query.ts @@ -558,6 +558,7 @@ const GET_UNAPPROVED_MEMES_COUNT = gql` } ) { data { + id approvedInRootPost } } @@ -579,7 +580,7 @@ export const getUnapprovedMemesCountQuery = createQuery({ if (post.approvedInRootPost) approved++ else unapproved++ }) - return { unapproved, approved } + return { unapproved, approved, ids: res.posts.data.map((post) => post.id) } }, defaultConfigGenerator: (params) => ({ enabled: !!params?.address && !!params.chatId, From 7e5053f3fa2b53a14a1dac1b5475140275e00fd8 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Mon, 15 Jul 2024 21:14:43 +0700 Subject: [PATCH 21/26] Fix type errro --- src/services/datahub/posts/subscription.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/datahub/posts/subscription.tsx b/src/services/datahub/posts/subscription.tsx index f20af9714..cd1660eef 100644 --- a/src/services/datahub/posts/subscription.tsx +++ b/src/services/datahub/posts/subscription.tsx @@ -218,6 +218,7 @@ async function processMessage( queryClient, { address: ownerId, chatId: rootPostId ?? '' }, (count) => ({ + ids: [...(count?.ids ?? []), entity.id], unapproved: (count?.unapproved ?? 0) + 1, approved: count?.approved ?? 0, }) From 93631a2e5cb4497ec8a2bf426a795288b3d05dc7 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Mon, 15 Jul 2024 21:52:59 +0700 Subject: [PATCH 22/26] Add approved count after success approve --- src/services/datahub/events/subscription.tsx | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/services/datahub/events/subscription.tsx b/src/services/datahub/events/subscription.tsx index c723a93c2..2e2f97122 100644 --- a/src/services/datahub/events/subscription.tsx +++ b/src/services/datahub/events/subscription.tsx @@ -20,6 +20,7 @@ import { } from '../generated-query' import { getSocialProfileQuery } from '../identity/query' import { callIdToPostIdMap } from '../posts/mutation' +import { getUnapprovedMemesCountQuery } from '../posts/query' import { getProfileQuery } from '../profiles/query' import { getGamificationTasksErrorQuery } from '../tasks/query' import { datahubSubscription } from '../utils' @@ -232,6 +233,36 @@ async function processSubscriptionEvent( return } + if (eventData.meta.callName === SocialCallName.SynthSetPostApproveStatus) { + const extension = eventData.meta.extension + const updatedPostId = extension?.postId ?? '' + const creatorAddress = extension?.creatorAddress ?? '' + const rootPostId = extension?.rootPostId ?? '' + const profile = getProfileQuery.getQueryData(client, creatorAddress) + toast.custom((t) => ( + + )) + getUnapprovedMemesCountQuery.setQueryData( + client, + { address: creatorAddress, chatId: rootPostId }, + (oldCount) => { + if (!oldCount) return oldCount + return { + ...oldCount, + ids: [...oldCount.ids, updatedPostId], + approved: oldCount.approved + 1, + } + } + ) + return + } + if (eventData.meta.callName === SocialCallName.SynthGamificationClaimTask) { claimTaskErrorStore.set(eventData.meta.code) From 81d5ae57850ffde035955d574670525229441b4c Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Mon, 15 Jul 2024 22:43:48 +0700 Subject: [PATCH 23/26] Fix issue with wording and invalidation --- src/components/modals/MemeOnReviewModal.tsx | 5 +++-- src/services/datahub/events/subscription.tsx | 3 +-- src/services/datahub/posts/subscription.tsx | 11 ++++------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/modals/MemeOnReviewModal.tsx b/src/components/modals/MemeOnReviewModal.tsx index 7f7fdaa1d..196ab7bf3 100644 --- a/src/components/modals/MemeOnReviewModal.tsx +++ b/src/components/modals/MemeOnReviewModal.tsx @@ -20,7 +20,8 @@ export default function MemeOnReviewModal({ enabled: props.isOpen, } ) - const remaining = MIN_MEME_FOR_REVIEW - (count?.unapproved ?? 0) + const sentMeme = (count?.unapproved ?? 0) + (count?.approved ?? 0) + const remaining = MIN_MEME_FOR_REVIEW - sentMeme const description = remaining > 0 @@ -32,7 +33,7 @@ export default function MemeOnReviewModal({ : `${ tokenomics?.socialActionPrice.createCommentPoints } points have been used. We received ${ - count?.unapproved ?? 0 + sentMeme ?? 0 } memes from you! Now we need a bit of time to finish review you as a verified creator.` return ( diff --git a/src/services/datahub/events/subscription.tsx b/src/services/datahub/events/subscription.tsx index 2e2f97122..dfe9ee758 100644 --- a/src/services/datahub/events/subscription.tsx +++ b/src/services/datahub/events/subscription.tsx @@ -235,7 +235,6 @@ async function processSubscriptionEvent( if (eventData.meta.callName === SocialCallName.SynthSetPostApproveStatus) { const extension = eventData.meta.extension - const updatedPostId = extension?.postId ?? '' const creatorAddress = extension?.creatorAddress ?? '' const rootPostId = extension?.rootPostId ?? '' const profile = getProfileQuery.getQueryData(client, creatorAddress) @@ -255,8 +254,8 @@ async function processSubscriptionEvent( if (!oldCount) return oldCount return { ...oldCount, - ids: [...oldCount.ids, updatedPostId], approved: oldCount.approved + 1, + unapproved: oldCount.unapproved - 1, } } ) diff --git a/src/services/datahub/posts/subscription.tsx b/src/services/datahub/posts/subscription.tsx index cd1660eef..704678659 100644 --- a/src/services/datahub/posts/subscription.tsx +++ b/src/services/datahub/posts/subscription.tsx @@ -239,11 +239,12 @@ async function processMessage( queryClient, { address: myAddress, chatId: rootPostId ?? '' } ) - if (count.unapproved === 1 || count.unapproved === 3) { + const sentMeme = count.approved + count.unapproved + if (sentMeme === 1 || sentMeme === 3) { useMessageData.getState().setOpenMessageModal('on-review') } else { const remaining = Math.max( - MIN_MEME_FOR_REVIEW - (count.unapproved ?? 0), + MIN_MEME_FOR_REVIEW - (sentMeme ?? 0), 0 ) const title = 'Under review' @@ -254,11 +255,7 @@ async function processMessage( } points have been used. We received your meme! We need at least ${remaining} more meme${ remaining > 1 ? 's' : '' } from you to mark you as a verified creator.` - : `${ - tokenomics.socialActionPrice.createCommentPoints - } points have been used. We received ${ - count ?? 0 - } memes from you! Now we need a bit of time to finish review you as a verified creator.` + : `${tokenomics.socialActionPrice.createCommentPoints} points have been used. We received ${sentMeme} memes from you! Now we need a bit of time to finish review you as a verified creator.` toast.custom((t) => ( Date: Mon, 15 Jul 2024 23:01:36 +0700 Subject: [PATCH 24/26] Fix issue with created Time --- src/components/extensions/common/CommonChatItem.tsx | 2 +- src/services/datahub/generated-query.ts | 2 ++ src/services/datahub/posts/subscription.tsx | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 874b133d7..9460230e4 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -127,7 +127,7 @@ export default function CommonChatItem({ const displayedTime = showApproveButton ? createdAtTime - : approvedInRootPostAtTime + : approvedInRootPostAtTime || createdAtTime const otherMessageCheckMarkElement = (className?: string) => ( Date: Mon, 15 Jul 2024 23:18:26 +0700 Subject: [PATCH 25/26] invalidate unapproved memes after block --- src/services/datahub/moderation/subscription.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/services/datahub/moderation/subscription.tsx b/src/services/datahub/moderation/subscription.tsx index 3f978f5bc..72af2c39a 100644 --- a/src/services/datahub/moderation/subscription.tsx +++ b/src/services/datahub/moderation/subscription.tsx @@ -15,6 +15,7 @@ import { SubscribeOrganizationSubscription, } from '../generated-query' import { isPersistentId } from '../posts/fetcher' +import { getUnapprovedMemesCountQuery } from '../posts/query' import { datahubSubscription, isDatahubAvailable } from '../utils' import { getBlockedInAppDetailedQuery, @@ -312,6 +313,11 @@ async function processBlockedResources( getPostQuery.fetchQuery(queryClient, entity.rootPostId), ] as const) + getUnapprovedMemesCountQuery.invalidate(queryClient, { + chatId: entity.rootPostId, + address: message?.struct.ownerId ?? '', + }) + if (message?.struct.ownerId === myAddress) { toast.custom((t) => ( Date: Mon, 15 Jul 2024 23:22:09 +0700 Subject: [PATCH 26/26] Move ref so unapproved meme count is fetched more eagerly --- src/components/extensions/common/CommonChatItem.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/extensions/common/CommonChatItem.tsx b/src/components/extensions/common/CommonChatItem.tsx index 9460230e4..a17f9d7ba 100644 --- a/src/components/extensions/common/CommonChatItem.tsx +++ b/src/components/extensions/common/CommonChatItem.tsx @@ -179,7 +179,7 @@ export default function CommonChatItem({ } return ( -
+
{isMyMessage && myMessageConfig.checkMark === 'adaptive-inside' && (