| import React from 'react'; |
| import { StyleSheet, View } from 'react-native'; |
| import { useTheme, Surface, Text } from 'react-native-paper'; |
| import type { Message } from '../../types/chat'; |
| import { formatChatTimestamp } from '../../utils/dateFormat'; |
|
|
| export interface MessageBubbleProps { |
| |
| message: Message; |
| |
| isOwn: boolean; |
| |
| otherUserName?: string; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function MessageBubble({ message, isOwn, otherUserName }: MessageBubbleProps) { |
| const theme = useTheme(); |
|
|
| |
| if (message.type !== 'text') return null; |
|
|
| const bubbleBg = isOwn |
| ? theme.colors.primaryContainer |
| : theme.colors.surfaceContainerHigh; |
| const textColor = isOwn |
| ? theme.colors.onPrimaryContainer |
| : theme.colors.onSurface; |
|
|
| |
| |
| const tailRadius = 4; |
| const baseRadius = 16; |
|
|
| return ( |
| <View |
| style={[ |
| styles.wrapper, |
| isOwn ? styles.ownWrapper : styles.otherWrapper, |
| ]} |
| > |
| {/* Show other user's name above their messages */} |
| {!isOwn && otherUserName ? ( |
| <Text |
| variant="labelSmall" |
| style={[styles.senderName, { color: theme.colors.primary }]} |
| > |
| {otherUserName} |
| </Text> |
| ) : null} |
| |
| <Surface |
| style={[ |
| styles.bubble, |
| { |
| backgroundColor: bubbleBg, |
| borderTopLeftRadius: isOwn ? baseRadius : tailRadius, |
| borderTopRightRadius: isOwn ? tailRadius : baseRadius, |
| borderBottomLeftRadius: baseRadius, |
| borderBottomRightRadius: baseRadius, |
| }, |
| ]} |
| elevation={0} |
| > |
| <Text |
| variant="bodyMedium" |
| style={{ color: textColor }} |
| > |
| {message.content} |
| </Text> |
| <View style={[styles.timestampRow, isOwn && styles.ownTimestampRow]}> |
| <Text |
| variant="labelSmall" |
| style={[styles.timestamp, { color: textColor, opacity: 0.7 }]} |
| > |
| {formatChatTimestamp(message.createdAt)} |
| </Text> |
| {isOwn && ( |
| <Text |
| variant="labelSmall" |
| style={[styles.checkmark, { color: textColor, opacity: 0.7 }]} |
| > |
| {message.isSent ? (message.isRead ? '✓✓' : '✓') : '⏳'} |
| </Text> |
| )} |
| </View> |
| </Surface> |
| </View> |
| ); |
| } |
|
|
| const styles = StyleSheet.create({ |
| wrapper: { |
| maxWidth: '80%', |
| marginBottom: 6, |
| }, |
| ownWrapper: { |
| alignSelf: 'flex-end', |
| }, |
| otherWrapper: { |
| alignSelf: 'flex-start', |
| }, |
| senderName: { |
| marginBottom: 4, |
| marginLeft: 4, |
| }, |
| bubble: { |
| paddingHorizontal: 14, |
| paddingTop: 10, |
| paddingBottom: 6, |
| minHeight: 36, |
| justifyContent: 'center', |
| }, |
| timestampRow: { |
| flexDirection: 'row', |
| alignItems: 'center', |
| justifyContent: 'flex-end', |
| gap: 4, |
| marginTop: 4, |
| }, |
| ownTimestampRow: { |
| justifyContent: 'flex-end', |
| }, |
| timestamp: { |
| fontSize: 10, |
| }, |
| checkmark: { |
| fontSize: 10, |
| }, |
| }); |
|
|