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

feat: wire up message item #1272

Open
wants to merge 35 commits into
base: mobile-app
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e64b9e3
Merge branch 'profile-actions' into chat-message-item-actions-drawer
pranavmene2000 Dec 24, 2024
513614a
feat(mobile): add actions to channel/dm item message
pranavmene2000 Dec 26, 2024
182032d
fix: increase emoji drawer close duration
pranavmene2000 Dec 26, 2024
bcdcb3f
feat: optimize emoji-picker
pranavmene2000 Dec 26, 2024
be4823d
feat: uncomment logs
pranavmene2000 Dec 27, 2024
a7df96a
feat: update details for forwarded-message
pranavmene2000 Dec 27, 2024
7a29400
feat: show Alert on delete message action
pranavmene2000 Dec 27, 2024
e394216
fix: actions spacing
pranavmene2000 Dec 27, 2024
ed44c9c
Merge remote-tracking branch 'origin/mobile-app' into chat-message-it…
pranavmene2000 Jan 3, 2025
603a09b
Merge branch 'chat-message-item-actions-drawer' into doctype-renderer
pranavmene2000 Jan 10, 2025
de8ba4d
fix: channelIcon
pranavmene2000 Jan 10, 2025
af6e587
feat: DocTypeLink renderer
pranavmene2000 Jan 10, 2025
e1bc760
feat: action icons styling
pranavmene2000 Jan 10, 2025
3752081
Merge remote-tracking branch 'origin/doctype-renderer' into wire-up-m…
prathameshkurunkar7 Jan 17, 2025
08a039d
Merge remote-tracking branch 'origin/link-preview' into wire-up-messa…
prathameshkurunkar7 Jan 17, 2025
71a9c7a
feat: enhance DoctypeLinkRenderer implementation and ui alignment
prathameshkurunkar7 Jan 24, 2025
cb32f70
fix: adjust layout and text truncation in DocTypeLink component
prathameshkurunkar7 Jan 24, 2025
f49bd4b
refactor: rename and edit folder structure for DocTypeLinkRenderer
prathameshkurunkar7 Jan 24, 2025
647156c
chore: update dependencies add htmlparser2 to mobile package.json
prathameshkurunkar7 Jan 24, 2025
f0e159d
feat: add LinkPreview component for enhanced link display in chat stream
prathameshkurunkar7 Jan 24, 2025
afa517d
fix: update PollMessage styling for improved layout and appearance
prathameshkurunkar7 Jan 24, 2025
7c30670
feat: implement MessageContentRenderer to display message text and li…
prathameshkurunkar7 Jan 24, 2025
a41c064
feat: enhance MessageItem component to show linkpreview, doctypelink,…
prathameshkurunkar7 Jan 24, 2025
f86085b
chore: modify folder structure for Renderers
prathameshkurunkar7 Jan 24, 2025
9b266e9
feat: add ReplyMessageBox component
prathameshkurunkar7 Jan 24, 2025
14984f4
feat: improve ReplyMessageBox styling and date formatting
prathameshkurunkar7 Jan 31, 2025
e38718b
Merge branch 'mobile-app' into wire-up-message-item
prathameshkurunkar7 Jan 31, 2025
cce2acc
feat(mobile): Add pinned message indicator to MessageItem
prathameshkurunkar7 Jan 31, 2025
ef4a378
feat: add UniversalFileIcon component
prathameshkurunkar7 Jan 31, 2025
7ed21ae
feat(mobile): add file message renderer
prathameshkurunkar7 Jan 31, 2025
94601ba
fix(mobile): improve message header spacing
prathameshkurunkar7 Jan 31, 2025
f8bb574
feat(mobile): add ImageMessageRenderer component for chat messages
prathameshkurunkar7 Jan 31, 2025
4692f2b
Merge branch 'mobile-app' into wire-up-message-item
prathameshkurunkar7 Jan 31, 2025
bffc473
feat: ignore link preview for links with file extensions
prathameshkurunkar7 Jan 31, 2025
56fcb8e
perf: memoize MessageItem component to optimize rendering
prathameshkurunkar7 Jan 31, 2025
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
2 changes: 1 addition & 1 deletion apps/mobile/app/[site_id]/chat/[id]/file-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const FileViewer = () => {
return (
<>
<Stack.Screen options={{
title: 'Raven',
title: 'File Viewer',
headerShown: showHeader,
headerTitle: `${uri?.split('/').pop()}`,
headerRight: () => <ShareButton uri={uri} />
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/app/[site_id]/forward-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,4 @@ const ChannelRow = React.memo(({ item, handleChannelSelect, currentUserInfo }: a
)
})

export default ForwardMessage
export default ForwardMessage
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/AudioIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/BarChart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/DocIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/FileIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/ImageIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/LinkExternalIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/PdfIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/PushPin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/ShareForward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/SheetIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/SlideIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/TxtIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/VideoIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/icons/ZipIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions apps/mobile/components/common/DIvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { View, ViewProps } from "react-native"
import { useColorScheme } from "@hooks/useColorScheme"

export const Divider = ({ ...props }: ViewProps) => {
const { colors } = useColorScheme()
return (
<View
style={{
borderBottomWidth: 1,
borderBottomColor: colors.grey5,
marginHorizontal: 16
}}
{...props}
/>
)
}
56 changes: 56 additions & 0 deletions apps/mobile/components/common/UniversalFileIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { getFileExtension } from "@raven/lib/utils/operations"
import { SvgProps } from "react-native-svg"
import FileIcon from "@assets/icons/FileIcon.svg"
import DocIcon from "@assets/icons/DocIcon.svg"
import TxtIcon from "@assets/icons/TxtIcon.svg"
import ImageIcon from "@assets/icons/ImageIcon.svg"
import ZipIcon from "@assets/icons/ZipIcon.svg"
import PdfIcon from "@assets/icons/PdfIcon.svg"
import SheetIcon from "@assets/icons/SheetIcon.svg"
import SlideIcon from "@assets/icons/SlideIcon.svg"
import VideoIcon from "@assets/icons/VideoIcon.svg"
import AudioIcon from "@assets/icons/AudioIcon.svg"

interface FileIconProps extends SvgProps {
fileName: string
}

const UniversalFileIcon = ({ fileName, ...props }: FileIconProps) => {

const extension = getFileExtension(fileName)

switch (extension) {
case 'pdf':
return <PdfIcon {...props} fill={'#E5484D'} />
case 'doc':
case 'docx':
return <DocIcon {...props} fill={'#8EC8F6'} />
case 'xls':
case 'xlsx':
case 'csv':
return <SheetIcon {...props} stroke={'#30A46C'} />
case 'ppt':
case 'pptx':
case 'key':
return <SlideIcon {...props} fill={'#EC9455'} />
case 'txt':
return <TxtIcon {...props} fill={'#B8BCBA'} />
case 'zip':
case 'rar':
return <ZipIcon {...props} fill={'#FBE577'} />
case 'mp3':
return <AudioIcon {...props} stroke={'#D0CDD7'} />
case 'mp4':
case 'webm':
return <VideoIcon {...props} stroke={'#EAACC3'} />
case 'jpg':
case 'jpeg':
case 'png':
case 'gif':
return <ImageIcon {...props} fill={'#60B3D7'} />
default:
return <FileIcon {...props} fill={'#B8BCBA'} />
}
}

export default UniversalFileIcon
8 changes: 7 additions & 1 deletion apps/mobile/components/features/chat-stream/ChatStream.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,20 @@ const ContentContainerStyles = {
}

const MessageContentRenderer = ({ item }: { item: MessageDateBlock }) => {

// TODO: Implement reply message press
const onReplyMessagePress = () => {
console.log('reply message pressed')
}

if (item.message_type === 'date') {
return <DateSeparator item={item} />
}

if (item.message_type === 'System') {
return <SystemMessageBlock item={item} />
}
return <MessageItem message={item} />
return <MessageItem message={item} onReplyMessagePress={onReplyMessagePress} />
}

export default ChatStream
70 changes: 59 additions & 11 deletions apps/mobile/components/features/chat-stream/MessageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { FileMessage, ImageMessage, PollMessage, TextMessage } from '@raven/types/common/Message'
import { View } from 'react-native'
import MessageAvatar from './MessageItemElements/MessageAvatar'
import { Text } from '@components/nativewindui/Text';
import { useGetUser } from '@raven/lib/hooks/useGetUser'
import MessageHeader from './MessageItemElements/MessageHeader'
import FileMessageRenderer from './MessageItemElements/FileMessageRenderer'
import MessageTextRenderer from './MessageItemElements/MessageTextRenderer'
import clsx from 'clsx'
import ShareForward from '@assets/icons/ShareForward.svg'
import { useMemo, memo } from 'react';
import PushPin from '@assets/icons/PushPin.svg'
import { FileMessage, ImageMessage, PollMessage, TextMessage } from '@raven/types/common/Message'
import MessageAvatar from '@components/features/chat-stream/MessageItemElements/MessageAvatar'
import MessageHeader from '@components/features/chat-stream/MessageItemElements/MessageHeader'
import FileMessageRenderer from '@components/features/chat/ChatMessage/Renderers/FileMessageRenderer'
import { MessageContentRenderer } from '@components/features/chat-stream/MessageItemElements/MessageContentRenderer'
import DocTypeLinkRenderer from '@components/features/chat/ChatMessage/Renderers/DocTypeLinkRenderer'
import { PollMessageBlock } from '@components/features/chat/ChatMessage/Renderers/PollMessage'
import ReplyMessageBox from '@components/features/chat/ChatMessage/ReplyMessageBox/ReplyMessageBox';
import { ImageMessageRenderer } from '@components/features/chat/ChatMessage/Renderers/ImageMessage';

type Props = {
message: FileMessage | PollMessage | TextMessage | ImageMessage
message: FileMessage | PollMessage | TextMessage | ImageMessage,
onReplyMessagePress: () => void
}

const MessageItem = ({ message }: Props) => {
const MessageItem = memo(({ message, onReplyMessagePress }: Props) => {

const { linked_message, replied_message_details } = message

const username = message.bot || message.owner

const user = useGetUser(username)

const userFullName = user?.full_name || username

const replyMessageDetails = useMemo(() => {
if (typeof replied_message_details === 'string') {
return JSON.parse(replied_message_details)
} else {
return replied_message_details
}
}, [replied_message_details])


return (
<View className={clsx('flex-1 flex-row px-2 gap-1', message.is_continuation ? 'pt-0' : 'pt-2')}>
<MessageAvatar
Expand All @@ -29,18 +49,46 @@ const MessageItem = ({ message }: Props) => {
botID={message.bot}
is_continuation={message.is_continuation}
/>
<View className='flex-1 items-start'>
<View className='flex-1 items-start gap-1'>
<MessageHeader
is_continuation={message.is_continuation}
userFullName={userFullName}
timestamp={message.formattedTime || ''}
/>
{message.message_type === 'File' ? <FileMessageRenderer message={message} /> : null}
{message.text ? <MessageTextRenderer text={message.text} /> : null}
{message.is_forwarded === 1 &&
<View className='flex-row items-center gap-1'>
<ShareForward fill={'#6b7280'} width={12} height={12} />
<Text className='text-xs text-gray-500 dark:text-gray-400'>
forwarded
</Text>
</View>}
{message.is_pinned === 1 &&
<View className='flex-row items-center gap-1'>
<PushPin width={12} height={12} />
<Text className='text-xs text-accent'>Pinned</Text>
</View>}

{linked_message && replied_message_details && <ReplyMessageBox
className='mb-1'
onPress={onReplyMessagePress}
message={replyMessageDetails}
/>
}

{message.text ? <MessageContentRenderer message={message} showLinkPreview={!message.hide_link_preview} /> : null}
{message.message_type === 'Image' && <ImageMessageRenderer message={message} />}
{message.message_type === 'File' && <FileMessageRenderer message={message} />}
{message.message_type === 'Poll' && <PollMessageBlock message={message} />}

{message.link_doctype && message.link_document && <View className={clsx(message.is_continuation ? 'ml-0.5' : '-ml-0.5')}>
<DocTypeLinkRenderer doctype={message.link_doctype} docname={message.link_document} />
</View>}

{message.is_edited === 1 && <Text className='text-xs text-gray-500 dark:text-gray-400'>(edited)</Text>}
{/* <Text>{message.text}</Text> */}
</View>
</View>
)
}
})

export default MessageItem

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Message } from "@raven/types/common/Message"
import LinkPreview from "@components/features/chat/ChatMessage/Renderers/LinkPreview"
import MessageTextRenderer from "@components/features/chat-stream/MessageItemElements/MessageTextRenderer"
import * as htmlparser2 from 'htmlparser2';
import { ALLOWED_FILE_EXTENSIONS, getFileExtension } from "@raven/lib/utils/operations";

type MessageContentRendererProps = {
message: Message,
showLinkPreview: boolean
}


export const MessageContentRenderer = ({ message, showLinkPreview }: MessageContentRendererProps) => {

const firstLink = extractFirstLink(message.text)

if (showLinkPreview && firstLink) {
return <LinkPreview messageID={message.name} href={firstLink} />
}
return (
<MessageTextRenderer text={message.text} />
)
}

// in message search for first link and extract href to show link preview
const extractFirstLink = (html: string): string | null => {
let firstLink: string | null = null

const parser = new htmlparser2.Parser({
onopentag(name, attributes) {
if (!firstLink && name === 'a' && attributes.href) {
// Ignore mailto: links and ensure it's an http(s) link and does not end with a file extension
const fileExtension = getFileExtension(attributes.href)
// if file-extension is one of the allowed file extensions, ignore the link
if (fileExtension && ALLOWED_FILE_EXTENSIONS.includes(fileExtension)) {
return
}

if (!attributes.href.startsWith('mailto:') &&
(attributes.href.startsWith('http://') ||
attributes.href.startsWith('https://'))) {
firstLink = attributes.href
}
}
}
})

parser.write(html)
parser.end()

return firstLink
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ type Props = {

const MessageHeader = ({ is_continuation, userFullName, timestamp }: Props) => {

if (is_continuation) return null
if (is_continuation) return <View className='mt-1' />

return (
<View className='flex-row gap-2 items-baseline pb-1'>
<Text className='font-medium text-sm'>{userFullName}</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const TAG_BASE_STYLES: TRenderEngineConfig['tagsStyles'] = {
const lightThemeTagStyles = {
'a': {
color: 'rgb(87, 83, 198)',
borderBottomColor: 'rgba(87, 83, 198, 0.8)',
borderBottomWidth: 0,
},
'blockquote': {
borderLeftColor: 'rgba(87, 83, 198, 0.5)',
Expand All @@ -76,7 +76,7 @@ const lightThemeTagStyles = {
const darkThemeTagStyles = {
'a': {
color: '#B1A9FF',
borderBottomColor: '#B1A9FF88',
borderBottomWidth: 0,
},
'blockquote': {
borderLeftColor: '#6E6ADE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { Message } from '@raven/types/common/Message'
import { Text, Pressable, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import QuickReactions from './QuickActions/QuickReactions'
import ReplyIcon from "@assets/icons/ReplyIcon.svg"
import ForwardIcon from "@assets/icons/ForwardIcon.svg"
import CopyIcon from "@assets/icons/CopyIcon.svg"
import BookMarkMinusIcon from "@assets/icons/BookMarkMinusIcon.svg"
import BookMarkPlusIcon from "@assets/icons/BookMarkPlusIcon.svg"
import PaperClipIcon from "@assets/icons/PaperClipIcon.svg"
import TrashIcon from "@assets/icons/TrashIcon.svg"
import DownloadIcon from "@assets/icons/DownloadIcon.svg"
import ArrowBackRetractIcon from "@assets/icons/ArrowBackRetractIcon.svg"
import MessageIcon from "@assets/icons/MessageIcon.svg"
import { ActivityIndicator } from '@components/nativewindui/ActivityIndicator'
Expand Down
Loading