Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/epic-base' into deploy/epic
Browse files Browse the repository at this point in the history
  • Loading branch information
samchuk-vlad committed Jul 24, 2024
2 parents 027f50a + 1c13489 commit bb0dbca
Show file tree
Hide file tree
Showing 25 changed files with 354 additions and 150 deletions.
56 changes: 56 additions & 0 deletions src/components/BottomDrawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { cx } from '@/utils/class-names'
import { Transition } from '@headlessui/react'
import { createPortal } from 'react-dom'
import { HiXMark } from 'react-icons/hi2'
import Button from './Button'
import { ModalFunctionalityProps, ModalProps } from './modals/Modal'

export default function BottomDrawer({
isOpen,
children,
closeModal,
title,
description,
}: ModalFunctionalityProps &
Pick<ModalProps, 'title' | 'description' | 'children'>) {
return createPortal(
<>
<Transition
show={isOpen}
appear
className='fixed inset-0 z-40 h-full w-full bg-black/50 backdrop-blur-md transition duration-300'
enterFrom={cx('opacity-0')}
enterTo='opacity-100'
leaveFrom='h-auto'
leaveTo='opacity-0 !duration-150'
onClick={closeModal}
/>
<Transition
show={isOpen}
appear
className='fixed bottom-0 left-1/2 z-40 mx-auto flex h-auto w-full max-w-screen-md -translate-x-1/2 rounded-t-[10px] bg-background-light outline-none transition duration-300'
enterFrom={cx('opacity-0 translate-y-48')}
enterTo='opacity-100 translate-y-0'
leaveFrom='h-auto'
leaveTo='opacity-0 translate-y-24 !duration-150'
>
<Button
size='circleSm'
variant='transparent'
className='absolute right-4 top-4'
onClick={closeModal}
>
<HiXMark className='text-lg' />
</Button>
<div className='mx-auto flex w-full max-w-screen-md flex-col gap-6 overflow-auto px-5 py-6 pb-6'>
<div className='flex flex-col gap-2'>
<span className='text-2xl font-medium'>{title}</span>
<span className='text-text-muted'>{description}</span>
</div>
<div className='flex w-full flex-col'>{children}</div>
</div>
</Transition>
</>,
document.body
)
}
21 changes: 9 additions & 12 deletions src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Component } from 'react'
import Card from './Card'
import LinkText from './LinkText'
import Button from './Button'
import Logo from './Logo'

export default class ErrorBoundary extends Component<any, any> {
Expand All @@ -27,16 +26,14 @@ export default class ErrorBoundary extends Component<any, any> {
<div className='flex flex-col gap-4'>
<Logo className='text-5xl' />
<p className='text-2xl'>Oops, something went wrong 🥲</p>
<p>
If you encounter this message inside Iframe, please enable cookies
</p>
<Card>
Go to{' '}
<LinkText href='chrome://settings/cookies' openInNewTab>
chrome://settings/cookies
</LinkText>{' '}
and uncheck &quot;Block third-party cookies&quot; option
</Card>
<Button
onClick={() => {
window.location.href = '/tg'
}}
size='lg'
>
Back to home
</Button>
</div>
</div>
)
Expand Down
27 changes: 19 additions & 8 deletions src/components/MenuList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const menuListItemStyles = cva<MenuListVariants>(
)

type Menu = {
isSeparator?: boolean
text: string | JSX.Element
iconClassName?: string
icon?: React.ComponentType<{ className?: string }>
Expand All @@ -69,14 +70,24 @@ export default function MenuList({
}: MenuListProps) {
return (
<div {...props} className={cx(menuListStyles({ size }), props.className)}>
{menus.map((menu, idx) => (
<MenuButton
key={idx}
menu={menu}
size={size}
closeFloatingMenu={closeFloatingMenu}
/>
))}
{menus.map((menu, idx) => {
if (menu.isSeparator) {
return (
<div
key={idx}
className='mx-2 my-1.5 border-b border-border-gray'
/>
)
}
return (
<MenuButton
key={idx}
menu={menu}
size={size}
closeFloatingMenu={closeFloatingMenu}
/>
)
})}
</div>
)
}
Expand Down
13 changes: 13 additions & 0 deletions src/components/chats/ChatForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,19 @@ export default function ChatForm({
return
}

const linkRegex = /(https?:\/\/[^\s]+)/g
if (linkRegex.test(messageParams.message ?? '')) {
toast.custom((t) => (
<Toast
t={t}
type='error'
title='No Links Allowed!'
description="Looks like you tried to send a link. We're keeping it link-free here! Please remove the link and try again. 😊"
/>
))
return
}

unsentMessageStorage.set(JSON.stringify(messageParams), chatId)
hasSentMessageStorage.set('true')

Expand Down
120 changes: 81 additions & 39 deletions src/components/chats/ChatItem/ChatItemMenus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ 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'
import { useExtensionData } from '@/stores/extension'
import { useMessageData } from '@/stores/message'
import { useMyMainAddress } from '@/stores/my-account'
import { cx } from '@/utils/class-names'
import { getIpfsContentUrl } from '@/utils/ipfs'
Expand All @@ -32,6 +34,7 @@ import { copyToClipboard } from '@/utils/strings'
import { Transition } from '@headlessui/react'
import { ImageProperties, PostData } from '@subsocial/api/types'
import { SocialCallDataArgs } from '@subsocial/data-hub-sdk'
import dayjs from 'dayjs'
import { useEffect, useState } from 'react'
import { BsFillPinAngleFill } from 'react-icons/bs'
import { FaCheck } from 'react-icons/fa6'
Expand All @@ -42,7 +45,7 @@ import {
HiOutlineInformationCircle,
} from 'react-icons/hi2'
import { IoDiamondOutline } from 'react-icons/io5'
import { LuShield } from 'react-icons/lu'
import { LuPencil, LuShield } from 'react-icons/lu'
import { MdContentCopy } from 'react-icons/md'
import { useInView } from 'react-intersection-observer'
import { toast } from 'sonner'
Expand Down Expand Up @@ -83,7 +86,14 @@ export default function ChatItemMenus({
getSocialProfileQuery.useQuery(ownerId, {
enabled: inView && isAdmin,
})
const isVerifiedUser =
socialProfile?.allowedCreateCommentRootPostIds.includes(chatId)

const { mutate: approveUser } = useApproveUser()
const setMessageToEdit = useMessageData((state) => state.setMessageToEdit)
const openExtensionModal = useExtensionData(
(state) => state.openExtensionModal
)

const { data: message } = getPostQuery.useQuery(messageId)
const [modalState, setModalState] = useState<ModalState>(null)
Expand All @@ -100,7 +110,7 @@ export default function ChatItemMenus({

const isOptimisticMessage = !dataType

const pinUnpinMenu = usePinUnpinMenuItem(chatId, messageId)
// const pinUnpinMenu = usePinUnpinMenuItem(chatId, messageId)
const getChatMenus = (): FloatingMenusProps['menus'] => {
const menus: FloatingMenusProps['menus'] = []

Expand All @@ -109,72 +119,99 @@ export default function ChatItemMenus({
icon: HiOutlineEyeSlash,
onClick: () => setModalState('hide'),
}
if (isMessageOwner && !isOptimisticMessage) menus.unshift(hideMenu)
const editItem: FloatingMenusProps['menus'][number] = {
text: 'Edit',
icon: LuPencil,
onClick: () => {
sendEvent('edit_message', { hubId, chatId })
setMessageToEdit(messageId)
openExtensionModal('subsocial-image', null)
},
}
if (isMessageOwner && !isOptimisticMessage) {
menus.unshift(hideMenu)

const createdTime = message?.struct.createdAtTime
const isApproved = message?.struct.approvedInRootPost

const isAfter5MinsOfCreation =
dayjs(createdTime).diff(dayjs(), 'minute') < 5

if (
(message?.content?.body.trim().length ?? 0) > 0 &&
((!isVerifiedUser && isAfter5MinsOfCreation && !isApproved) ||
(isVerifiedUser && isAfter5MinsOfCreation))
)
menus.unshift(editItem)
}

if (isAuthorized) {
menus.unshift({
icon: LuShield,
text: 'Moderate ...',
onClick: () => {
sendEvent('open_moderate_action_modal', { hubId, chatId })
setModalState('moderate')
},
})
menus.unshift({
if (menus.length > 0) {
menus.push({
isSeparator: true,
text: '',
})
}
if (!loadingSocialProfile && !isVerifiedUser) {
menus.push({
text: 'Approve User',
icon: FaCheck,
onClick: () => {
sendEvent('approve_user', { hubId, chatId })
approveUser({
address: ownerId,
allow: { createCommentRootPostIds: [chatId] },
})
},
})
}
menus.push({
icon: LuShield,
text: 'Block message',
text: 'Block user',
onClick: () => {
sendEvent('block_message', { hubId, chatId })
sendEvent('block_user', { hubId, chatId })
moderate({
callName: 'synth_moderation_block_resource',
args: {
reasonId: firstReasonId,
resourceId: messageId,
resourceId: ownerId,
ctxPostIds: ['*'],
ctxAppIds: ['*'],
},
chatId: chatId ?? '',
chatId,
})
},
})
menus.unshift({
menus.push({
icon: LuShield,
text: 'Block user',
text: 'Block message',
onClick: () => {
sendEvent('block_user', { hubId, chatId })
sendEvent('block_message', { hubId, chatId })
moderate({
callName: 'synth_moderation_block_resource',
args: {
reasonId: firstReasonId,
resourceId: ownerId,
resourceId: messageId,
ctxPostIds: ['*'],
ctxAppIds: ['*'],
},
chatId,
chatId: chatId ?? '',
})
},
})
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] },
})
},
})
}
menus.push({
icon: LuShield,
text: 'Moderate ...',
onClick: () => {
sendEvent('open_moderate_action_modal', { hubId, chatId })
setModalState('moderate')
},
})
}

if (isOptimisticMessage) return menus

if (pinUnpinMenu) menus.unshift(pinUnpinMenu)
// if (pinUnpinMenu) menus.unshift(pinUnpinMenu)

return menus
}
Expand Down Expand Up @@ -407,6 +444,7 @@ export function useModerateWithSuccessToast(messageId: string, chatId: string) {
ctxAppIds: ['*'],
},
chatId,
isUndo: true,
})

toast.custom((t) => (
Expand Down Expand Up @@ -442,7 +480,11 @@ export function useModerateWithSuccessToast(messageId: string, chatId: string) {
icon={(classNames) => (
<HiOutlineInformationCircle className={classNames} />
)}
title='Undo moderation success'
title={
variables.isUndo
? 'Undo moderation success'
: 'Unblock meme success'
}
/>
))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function ProfileDetailModal({
address,
...props
}: ModalFunctionalityProps & { address: string }) {
const { telegramLink, isLoading } = useTgLink(address)
const { telegramLink, isLoading } = useTgLink(address, true)
const { data: referralData } = getUserReferralsQuery.useQuery(address || '')
const isAdmin = useIsModerationAdmin()
if (!isAdmin) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {
<Name address={address} className='!text-text' clipText />
{isAdmin ? (
<UnapprovedMemeCount
className='bg-transparent p-0 text-text-muted'
className='flex-shrink-0 bg-transparent p-0 text-text-muted'
address={address}
chatId={chatId}
/>
Expand Down Expand Up @@ -182,7 +182,7 @@ const ProfilePostsListModal = ({ tabsConfig }: ProfilePostsListModalProps) => {
<Button
size='md'
variant='redOutline'
className='w-fit text-red-400'
className='w-fit px-3 text-red-400'
onClick={onBlockUserClick}
>
Block user
Expand Down
2 changes: 1 addition & 1 deletion src/components/chats/ChatList/ChatList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function ChatListContent({
sendEvent('load_more_messages', { currentPage })
}}
className={cx(
'relative flex w-full flex-col-reverse !overflow-hidden pb-2',
'relative flex w-full flex-col-reverse !overflow-hidden',
// need to have enough room to open message menu
'min-h-[400px]'
)}
Expand Down
Loading

0 comments on commit bb0dbca

Please sign in to comment.