diff --git a/jest/fixtures.ts b/jest/fixtures.ts
index a89768a..a61900b 100644
--- a/jest/fixtures.ts
+++ b/jest/fixtures.ts
@@ -2,11 +2,11 @@ import { MessageType, Size, User } from '../src/types'
export const fileMessage: MessageType.File = {
authorId: 'userId',
- id: 'uuidv4',
+ fileName: 'flyer.pdf',
+ id: 'file-uuidv4',
mimeType: 'application/pdf',
- name: 'flyer.pdf',
size: 15000,
- timestamp: 0,
+ timestamp: 2000000,
type: 'file',
url: 'file:///Users/admin/flyer.pdf',
}
@@ -14,7 +14,9 @@ export const fileMessage: MessageType.File = {
export const imageMessage: MessageType.Image = {
authorId: 'userId',
height: 100,
- id: 'uuidv4',
+ id: 'image-uuidv4',
+ imageName: 'imageName',
+ size: 15000,
timestamp: 0,
type: 'image',
url: 'https://avatars1.githubusercontent.com/u/59206044',
diff --git a/package.json b/package.json
index eb37c31..57f56f7 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"dependencies": {
"@flyerhq/react-native-keyboard-accessory-view": "^1.5.1",
"@flyerhq/react-native-link-preview": "^1.0.2",
+ "dayjs": "^1.9.1",
"react-native-image-viewing": "^0.2.0",
"react-native-parsed-text": "^0.0.22"
},
diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx
index 9559675..d849d13 100644
--- a/src/components/Chat/Chat.tsx
+++ b/src/components/Chat/Chat.tsx
@@ -2,6 +2,8 @@ import {
useComponentSize,
usePanResponder,
} from '@flyerhq/react-native-keyboard-accessory-view'
+import dayjs from 'dayjs'
+import calendar from 'dayjs/plugin/calendar'
import * as React from 'react'
import {
FlatList,
@@ -10,6 +12,7 @@ import {
StatusBar,
StatusBarProps,
StyleSheet,
+ Text,
View,
} from 'react-native'
import ImageView from 'react-native-image-viewing'
@@ -19,6 +22,8 @@ import { Input, InputAdditionalProps, InputTopLevelProps } from '../Input'
import { Message, MessageTopLevelProps } from '../Message'
import styles from './styles'
+dayjs.extend(calendar)
+
export type ChatTopLevelProps = InputTopLevelProps & MessageTopLevelProps
export interface ChatProps extends ChatTopLevelProps {
@@ -92,22 +97,64 @@ export const Chat = ({
index: number
}) => {
const messageWidth = Math.floor(Math.min(size.width * 0.77, 440))
- const previousMessageSameAuthor =
- messages[index - 1]?.authorId === message.authorId
+ // TODO: Update the logic after pagination is introduced
+ const isFirst = index === 0
+ const isLast = index === messages.length - 1
+ const previousMessage = messages[index - 1]
+ const nextMessage = messages[index + 1]
+
+ let nextMessageDifferentDay = false
+ let nextMessageSameAuthor = false
+ let previousMessageSameAuthor = false
+ let previousMessageWithinTimeRange = false
+
+ if (!isLast) {
+ nextMessageDifferentDay = !dayjs
+ .unix(message.timestamp)
+ .isSame(dayjs.unix(nextMessage.timestamp), 'day')
+ nextMessageSameAuthor = nextMessage.authorId === message.authorId
+ }
+
+ if (!isFirst) {
+ previousMessageSameAuthor = previousMessage.authorId === message.authorId
+ previousMessageWithinTimeRange =
+ previousMessageSameAuthor &&
+ previousMessage.timestamp - message.timestamp < 3600
+ }
return (
-
+ <>
+
+ {(nextMessageDifferentDay || isLast) && (
+
+ {dayjs.unix(message.timestamp).calendar(undefined, {
+ sameDay: '[Today]',
+ nextDay: 'DD MMMM',
+ nextWeek: 'DD MMMM',
+ lastDay: '[Yesterday]',
+ lastWeek: 'DD MMMM',
+ sameElse: 'DD MMMM',
+ })}
+
+ )}
+ >
)
}
diff --git a/src/components/Chat/__tests__/Chat.test.tsx b/src/components/Chat/__tests__/Chat.test.tsx
index dea679d..0ce7301 100644
--- a/src/components/Chat/__tests__/Chat.test.tsx
+++ b/src/components/Chat/__tests__/Chat.test.tsx
@@ -11,7 +11,7 @@ import { Chat } from '../Chat'
describe('chat', () => {
it('renders image preview', async () => {
expect.assertions(1)
- const messages = [imageMessage]
+ const messages = [textMessage, fileMessage, imageMessage]
const onSendPress = jest.fn()
const { getByRole, getByText } = render(
@@ -25,7 +25,7 @@ describe('chat', () => {
it('sends a text message', () => {
expect.assertions(1)
- const messages = [textMessage]
+ const messages = [textMessage, fileMessage, imageMessage]
const onSendPress = jest.fn()
const { getByLabelText } = render(
{
it('opens file on a file message tap', () => {
expect.assertions(1)
- const messages = [fileMessage]
+ const messages = [textMessage, fileMessage, imageMessage]
const onSendPress = jest.fn()
const onFilePress = jest.fn()
const { getByLabelText } = render(
diff --git a/src/components/Chat/styles.ts b/src/components/Chat/styles.ts
index 7f5c542..9bf42ca 100644
--- a/src/components/Chat/styles.ts
+++ b/src/components/Chat/styles.ts
@@ -4,8 +4,16 @@ export default StyleSheet.create({
container: {
flex: 1,
},
+ dateDivider: {
+ color: '#1d1c21',
+ fontSize: 12,
+ fontWeight: 'bold',
+ lineHeight: 16,
+ marginBottom: 32,
+ textAlign: 'center',
+ },
footer: {
- height: 24,
+ height: 16,
},
list: {
backgroundColor: '#fff',
diff --git a/src/components/ImageMessage/ImageMessage.tsx b/src/components/ImageMessage/ImageMessage.tsx
index 782927f..55c427e 100644
--- a/src/components/ImageMessage/ImageMessage.tsx
+++ b/src/components/ImageMessage/ImageMessage.tsx
@@ -31,7 +31,6 @@ export const ImageMessage = ({
const aspectRatio = size.width / (size.height || 1)
const isMinimized = aspectRatio < 0.1 || aspectRatio > 10
const {
- background,
image,
minimizedImage,
minimizedImageContainer,
@@ -80,11 +79,7 @@ export const ImageMessage = ({
) : (
-
+
{renderImage()}
diff --git a/src/components/ImageMessage/styles.ts b/src/components/ImageMessage/styles.ts
index c90619a..ae51fee 100644
--- a/src/components/ImageMessage/styles.ts
+++ b/src/components/ImageMessage/styles.ts
@@ -13,9 +13,6 @@ const styles = ({
user?: User
}) =>
StyleSheet.create({
- background: {
- flex: 1,
- },
image: {
aspectRatio,
maxHeight: messageWidth,
diff --git a/src/components/Message/Message.tsx b/src/components/Message/Message.tsx
index c0d5bd9..fbaf2a9 100644
--- a/src/components/Message/Message.tsx
+++ b/src/components/Message/Message.tsx
@@ -1,5 +1,6 @@
+import dayjs from 'dayjs'
import * as React from 'react'
-import { View } from 'react-native'
+import { Text, View } from 'react-native'
import { MessageType } from '../../types'
import { UserContext } from '../../utils'
import { FileMessage } from '../FileMessage'
@@ -28,6 +29,7 @@ export interface MessageProps extends MessageTopLevelProps {
messageWidth: number
onImagePress: (url: string) => void
previousMessageSameAuthor: boolean
+ previousMessageWithinTimeRange: boolean
}
export const Message = ({
@@ -36,15 +38,17 @@ export const Message = ({
onFilePress,
onImagePress,
previousMessageSameAuthor,
+ previousMessageWithinTimeRange,
renderFileMessage,
renderImageMessage,
renderTextMessage,
}: MessageProps) => {
const user = React.useContext(UserContext)
- const { container, contentContainer } = styles({
+ const { container, contentContainer, statusContainer, time } = styles({
message,
messageWidth,
previousMessageSameAuthor,
+ previousMessageWithinTimeRange,
user,
})
@@ -78,6 +82,13 @@ export const Message = ({
return (
{renderMessage()}
+ {!previousMessageWithinTimeRange && (
+
+
+ {dayjs.unix(message.timestamp).format('h:mm a')}
+
+
+ )}
)
}
diff --git a/src/components/Message/styles.ts b/src/components/Message/styles.ts
index 946c527..e8566fb 100644
--- a/src/components/Message/styles.ts
+++ b/src/components/Message/styles.ts
@@ -5,19 +5,22 @@ const styles = ({
message,
messageWidth,
previousMessageSameAuthor,
+ previousMessageWithinTimeRange,
user,
}: {
message: MessageType.Any
messageWidth: number
previousMessageSameAuthor: boolean
+ previousMessageWithinTimeRange: boolean
user?: User
}) =>
StyleSheet.create({
container: {
+ alignSelf: user?.id === message.authorId ? 'flex-end' : 'flex-start',
flex: 1,
- flexDirection: 'row',
- justifyContent: user?.id === message.authorId ? 'flex-end' : 'flex-start',
- marginBottom: previousMessageSameAuthor ? 8 : 24,
+ marginBottom:
+ previousMessageSameAuthor || previousMessageWithinTimeRange ? 8 : 16,
+ marginHorizontal: 24,
},
contentContainer: {
backgroundColor:
@@ -27,10 +30,20 @@ const styles = ({
borderBottomLeftRadius: user?.id === message.authorId ? 20 : 0,
borderBottomRightRadius: user?.id === message.authorId ? 0 : 20,
borderRadius: 20,
- marginHorizontal: 24,
maxWidth: messageWidth,
overflow: 'hidden',
},
+ statusContainer: {
+ alignSelf: 'flex-end',
+ marginRight: 8,
+ marginTop: 8,
+ },
+ time: {
+ color: '#9e9cab',
+ fontSize: 12,
+ fontWeight: '500',
+ lineHeight: 16,
+ },
})
export default styles
diff --git a/yarn.lock b/yarn.lock
index 24d7f1f..4d2fc28 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2407,6 +2407,11 @@ dayjs@^1.8.15:
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50"
integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==
+dayjs@^1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.9.1.tgz#201a755f7db5103ed6de63ba93a984141c754541"
+ integrity sha512-01NCTBg8cuMJG1OQc6PR7T66+AFYiPwgDvdJmvJBn29NGzIG+DIFxPLNjHzwz3cpFIvG+NcwIjP9hSaPVoOaDg==
+
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"