Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy/epic #692

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/components/chats/ChatItem/profilePosts/ProfileDetailModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import MenuList from '@/components/MenuList'
import ProfilePreview from '@/components/ProfilePreview'
import { Skeleton } from '@/components/SkeletonFallback'
import Modal, { ModalFunctionalityProps } from '@/components/modals/Modal'
import useIsModerationAdmin from '@/hooks/useIsModerationAdmin'
import useTgLink from '@/hooks/useTgLink'
import { getUserReferralsQuery } from '@/services/datahub/leaderboard/query'
import { formatNumber } from '@/utils/strings'
import { FaPaperPlane } from 'react-icons/fa6'

export default function ProfileDetailModal({
address,
...props
}: ModalFunctionalityProps & { address: string }) {
const { telegramLink, isLoading } = useTgLink(address)
const { data: referralData } = getUserReferralsQuery.useQuery(address || '')
const isAdmin = useIsModerationAdmin()
if (!isAdmin) return null

return (
<Modal {...props} title='Profile' withCloseButton>
<div className='flex flex-col gap-3 border-b border-b-border-gray pb-4'>
<ProfilePreview asLink address={address} />
<div className='grid grid-cols-1'>
<div className='grid grid-cols-[max-content_1fr] gap-2'>
<span className='text-text-muted'>Referrals Count</span>
<span>
<span className='text-text-muted'>: </span>
{referralData ? (
formatNumber(referralData.refCount)
) : (
<Skeleton />
)}
</span>
<span className='text-text-muted'>Points from Referral</span>
<span>
<span className='text-text-muted'>: </span>
{referralData ? (
formatNumber(referralData.pointsEarned)
) : (
<Skeleton />
)}
</span>
</div>
</div>
</div>
<MenuList
className='-mx-3 -mb-5 w-[calc(100%_+_1.5rem)] px-0'
menus={[
{
text: 'Message User',
icon: FaPaperPlane,
href: telegramLink,
disabled: isLoading,
},
]}
/>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import AddressAvatar from '@/components/AddressAvatar'
import Button from '@/components/Button'
import Name from '@/components/Name'
import SkeletonFallback from '@/components/SkeletonFallback'
import { env } from '@/env.mjs'
import useAuthorizedForModeration from '@/hooks/useAuthorizedForModeration'
import useIsModerationAdmin from '@/hooks/useIsModerationAdmin'
import { TabButton } from '@/modules/chat/HomePage/ChatTabs'
import { getModerationReasonsQuery } from '@/services/datahub/moderation/query'
import { getUserPostedMemesForCountQuery } from '@/services/datahub/posts/query'
import { getPaginatedPostIdsByPostIdAndAccount } from '@/services/datahub/posts/queryByAccount'
import { useSendEvent } from '@/stores/analytics'
import { useProfilePostsModal } from '@/stores/profile-posts-modal'
Expand All @@ -13,9 +16,13 @@ import { Transition } from '@headlessui/react'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
import { HiOutlineChevronLeft } from 'react-icons/hi2'
import SkeletonFallback from '../../../SkeletonFallback'
import {
HiOutlineChevronLeft,
HiOutlineInformationCircle,
} from 'react-icons/hi2'
import UnapprovedMemeCount from '../../UnapprovedMemeCount'
import { useModerateWithSuccessToast } from '../ChatItemMenus'
import ProfileDetailModal from './ProfileDetailModal'
import ProfilePostsList from './ProfilePostsList'

type Tab = 'all' | 'contest'
Expand All @@ -33,6 +40,7 @@ const chatIdByTab = {
}

const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {
const [isOpenDetail, setIsOpenDetail] = useState(false)
const [selectedTab, setSelectedTab] = useState<Tab>(
tabsConfig?.defaultTab || 'all'
)
Expand All @@ -51,16 +59,24 @@ const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {

const { mutate: moderate } = useModerateWithSuccessToast(messageId, chatId)
const sendEvent = useSendEvent()
const isAdmin = useIsModerationAdmin()
const { isAuthorized } = useAuthorizedForModeration(chatId)

const { data: reasons } = getModerationReasonsQuery.useQuery(null)
const firstReasonId = reasons?.[0].id
const { data: userPostedMemes, isLoading: loadingMemes } =
getUserPostedMemesForCountQuery.useQuery(
{
address,
chatId,
},
{ enabled: isOpen }
)

const { data, isLoading } =
getPaginatedPostIdsByPostIdAndAccount.useInfiniteQuery(chatId, address)

const totalPostsCount = data?.pages[0].totalData || 0

const { data: reasons } = getModerationReasonsQuery.useQuery(null)
const firstReasonId = reasons?.[0].id

const onBlockUserClick = () => {
sendEvent('block_user', { hubId, chatId })
moderate({
Expand Down Expand Up @@ -102,8 +118,13 @@ const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {
leaveFrom='h-auto'
leaveTo='opacity-0 -translate-y-24 !duration-150'
>
<ProfileDetailModal
isOpen={isOpenDetail}
closeModal={() => setIsOpenDetail(false)}
address={address}
/>
<div className='mx-auto flex w-full max-w-screen-md flex-1 flex-col overflow-auto'>
<div className='relative mx-auto flex w-full items-center justify-between gap-2 px-4 py-4'>
<div className='relative mx-auto flex w-full items-center justify-between gap-2 px-4 py-3'>
<div className='flex flex-1 items-center gap-2'>
<Button
variant='transparent'
Expand All @@ -122,29 +143,51 @@ const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {
address={address}
className='flex-shrink-0 cursor-pointer'
/>
<div className='flex flex-col gap-1'>
<div
className='flex flex-col gap-0.5'
onClick={() => {
if (isAdmin) setIsOpenDetail(true)
}}
>
<Name address={address} className='!text-text' clipText />
<span className='flex items-center gap-1 text-xs font-medium leading-[normal] text-slate-400'>
<span>Memes:</span>
<SkeletonFallback
isLoading={isLoading}
className='my-0 w-fit min-w-8'
>
{totalPostsCount}
</SkeletonFallback>
</span>
{isAdmin ? (
<UnapprovedMemeCount
className='bg-transparent p-0 text-text-muted'
address={address}
chatId={chatId}
/>
) : (
<span className='flex items-center gap-1 text-xs font-medium leading-[normal] text-slate-400'>
<span>Memes:</span>
<SkeletonFallback
isLoading={isLoading}
className='my-0 w-fit min-w-8'
>
{totalPostsCount}
</SkeletonFallback>
</span>
)}
</div>
</div>

{isAuthorized && (
<Button
size='md'
variant='redOutline'
className='w-fit text-red-400'
onClick={onBlockUserClick}
>
Block user
</Button>
<div className='flex items-center gap-2'>
<Button
size='circleSm'
variant='transparent'
onClick={() => setIsOpenDetail(true)}
>
<HiOutlineInformationCircle className='text-lg text-text-muted' />
</Button>
<Button
size='md'
variant='redOutline'
className='w-fit text-red-400'
onClick={onBlockUserClick}
>
Block user
</Button>
</div>
)}
</div>
<div className='relative mx-auto flex h-full max-h-full min-h-[400px] w-full flex-col items-center px-4'>
Expand Down
12 changes: 6 additions & 6 deletions src/components/chats/UnapprovedMemeCount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,20 @@ export default function UnapprovedMemeCount({
)}
>
<div className='flex items-center gap-1'>
<div className='flex items-center gap-1'>
<Image src={CheckImage} className='h-4 w-4' alt='' />
<span>{approved}</span>
</div>
<span className='text-text-muted'>/</span>
<div className='flex items-center gap-1'>
<Image src={ForbiddenImage} className='h-4 w-4' alt='' />
<span>{blocked}</span>
</div>
<span>/</span>
<span className='text-text-muted'>/</span>
<div className='flex items-center gap-1'>
<Image src={TimeImage} className='h-4 w-4' alt='' />
<span>{unapproved}</span>
</div>
<span>/</span>
<div className='flex items-center gap-1'>
<Image src={CheckImage} className='h-4 w-4' alt='' />
<span>{approved}</span>
</div>
</div>
</div>
)
Expand Down
9 changes: 3 additions & 6 deletions src/components/content-staking/SuperLike.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Thumbsup from '@/assets/emojis/thumbsup.png'
import { env } from '@/env.mjs'
import { useIsAddressBlockedInApp } from '@/hooks/useIsAddressBlockedInApp'
import { getPostQuery, getServerTimeQuery } from '@/services/api/query'
import { useCreateSuperLike } from '@/services/datahub/content-staking/mutation'
Expand All @@ -16,6 +15,7 @@ import { useLoginModal } from '@/stores/login-modal'
import { useMessageData } from '@/stores/message'
import { useMyAccount, useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { getIsContestEnded, getIsInContest } from '@/utils/contest'
import { currentNetwork } from '@/utils/network'
import { LocalStorage } from '@/utils/storage'
import dayjs from 'dayjs'
Expand Down Expand Up @@ -64,11 +64,8 @@ export function SuperLikeWrapper({
const { mutate: createSuperLike } = useCreateSuperLike()
const { data: superLikeCount } = getSuperLikeCountQuery.useQuery(postId)

const isInContest =
post?.struct.rootPostId === env.NEXT_PUBLIC_CONTEST_CHAT_ID
const isContestEnded = dayjs().isAfter(
dayjs(env.NEXT_PUBLIC_CONTEST_END_TIME)
)
const isInContest = getIsInContest(post?.struct.rootPostId ?? '')
const isContestEnded = getIsContestEnded()
const isInEndedContest = isInContest && isContestEnded

const { canBeLiked: canBeSuperliked, isLoading: loadingCanBeLiked } =
Expand Down
11 changes: 5 additions & 6 deletions src/components/extensions/common/CommonChatItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { getRepliedMessageId } from '@/components/chats/utils'
import SuperLike, {
SuperLikeButton,
} from '@/components/content-staking/SuperLike'
import { env } from '@/env.mjs'
import useAuthorizedForModeration from '@/hooks/useAuthorizedForModeration'
import useIsMessageBlocked from '@/hooks/useIsMessageBlocked'
import useIsModerationAdmin from '@/hooks/useIsModerationAdmin'
Expand All @@ -24,8 +23,8 @@ import {
import { isMessageSent } from '@/services/subsocial/commentIds/optimistic'
import { useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { getIsContestEnded, getIsInContest } from '@/utils/contest'
import { getTimeRelativeToNow } from '@/utils/date'
import dayjs from 'dayjs'
import Linkify from 'linkify-react'
import { useInView } from 'react-intersection-observer'
import { ExtensionChatItemProps } from '../types'
Expand Down Expand Up @@ -343,7 +342,7 @@ export default function CommonChatItem({
}}
size='sm'
className={cx(
'w-full whitespace-nowrap px-0 text-xs !text-text-red',
'w-full whitespace-nowrap px-0 text-sm !text-text-red',
{
['!bg-[#EF4444] disabled:border-none disabled:!text-white disabled:!ring-0 disabled:!brightness-100']:
isMessageBlocked,
Expand Down Expand Up @@ -436,15 +435,15 @@ function ApproveMemeButton({
messageId: string
}) {
const { mutate, isLoading } = useApproveMessage()
const isInContest = chatId === env.NEXT_PUBLIC_CONTEST_CHAT_ID
const isContestEnded = dayjs().isAfter(env.NEXT_PUBLIC_CONTEST_END_TIME)
const isInContest = getIsInContest(chatId)
const isContestEnded = getIsContestEnded()
const isInEndedContest = isInContest && isContestEnded

return (
<Button
variant='greenOutline'
size='sm'
className='whitespace-nowrap px-0 text-xs disabled:!border-text-muted disabled:!text-text-muted disabled:!ring-text-muted'
className='whitespace-nowrap px-0 text-sm disabled:!border-text-muted disabled:!text-text-muted disabled:!ring-text-muted'
loadingText='Approving...'
isLoading={isLoading}
disabled={isInEndedContest}
Expand Down
25 changes: 22 additions & 3 deletions src/modules/chat/HomePage/ChatContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Meme2EarnIntroModal, {
import Modal, { ModalFunctionalityProps } from '@/components/modals/Modal'
import { env } from '@/env.mjs'
import useIsAddressBlockedInChat from '@/hooks/useIsAddressBlockedInChat'
import useIsModerationAdmin from '@/hooks/useIsModerationAdmin'
import useLinkedEvmAddress from '@/hooks/useLinkedEvmAddress'
import usePostMemeThreshold from '@/hooks/usePostMemeThreshold'
import PointsWidget from '@/modules/points/PointsWidget'
Expand All @@ -20,6 +21,8 @@ import { useSendEvent } from '@/stores/analytics'
import { useExtensionData } from '@/stores/extension'
import { useMessageData } from '@/stores/message'
import { useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { getIsContestEnded } from '@/utils/contest'
import { useLocalStorage } from '@uidotdev/usehooks'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
Expand All @@ -43,12 +46,24 @@ const chatIdsBasedOnSelectedTab = {

export default function ChatContent({ className }: Props) {
const { query } = useRouter()
const isAdmin = useIsModerationAdmin()
let [selectedTab, setSelectedTab] = useLocalStorage<TabState>(
'memes-tab',
'all'
)
if (!tabStates.includes(selectedTab)) {
if (
!tabStates.includes(selectedTab) ||
(selectedTab === 'contest' && getIsContestEnded())
) {
selectedTab = 'all'
} else if (selectedTab === 'not-approved-contest' && getIsContestEnded()) {
selectedTab = 'not-approved'
}
if (
!isAdmin &&
(selectedTab === 'not-approved' || selectedTab === 'not-approved-contest')
) {
setSelectedTab('all')
}

useLayoutEffect(() => {
Expand Down Expand Up @@ -79,8 +94,12 @@ export default function ChatContent({ className }: Props) {

return (
<>
<PointsWidget isNoTgScroll className='sticky top-0' />
<Tabs selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
{!isAdmin && <PointsWidget isNoTgScroll className='sticky top-0' />}
<Tabs
selectedTab={selectedTab}
setSelectedTab={setSelectedTab}
className={cx(isAdmin && 'top-0')}
/>
<ChatRoom
scrollableContainerClassName='pt-12'
asContainer
Expand Down
Loading
Loading