feat(08-02): create JKChatMessage component

Create individual message display component with:
- Avatar with initials (first + last name initial)
- Sender name in bold
- Relative timestamp using formatTimestamp utility
- Message text with word wrapping
- Inline styles for MVP (SCSS styling deferred to Plan 8.3)
- React.memo for performance optimization
- PropTypes validation

Component follows established React patterns with functional components,
hooks, and proper documentation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-01-27 14:04:45 +05:30
parent 7264fcb8ee
commit a78d2bc52f
1 changed files with 87 additions and 0 deletions

View File

@ -0,0 +1,87 @@
import React from 'react';
import PropTypes from 'prop-types';
import { formatTimestamp } from '../../../utils/formatTimestamp';
/**
* Get initials for avatar from sender name
* Returns first letter of first and last name, or just first letter if single name
* @param {string} name - Sender name
* @returns {string} Initials (e.g., "JD" for "John Doe")
*/
const getInitials = (name) => {
if (!name) return '?';
const parts = name.trim().split(' ');
if (parts.length === 1) return parts[0][0].toUpperCase();
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
};
/**
* JKChatMessage - Individual message display component
*
* Displays a single chat message with avatar, sender name, message text, and timestamp.
*
* Features:
* - Avatar with initials (first + last name)
* - Sender name in bold
* - Relative timestamp (via formatTimestamp utility)
* - Message text with word wrapping
* - React.memo for performance optimization
*/
const JKChatMessage = ({ message }) => {
const { senderName, message: text, createdAt } = message;
return (
<div style={{
display: 'flex',
gap: '12px',
marginBottom: '16px',
padding: '8px',
borderRadius: '4px',
backgroundColor: '#f8f9fa'
}}>
{/* Avatar */}
<div style={{
width: '36px',
height: '36px',
borderRadius: '50%',
backgroundColor: '#007bff',
color: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: 'bold',
fontSize: '14px',
flexShrink: 0
}}>
{getInitials(senderName)}
</div>
{/* Message content */}
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'baseline', gap: '8px', marginBottom: '4px' }}>
<span style={{ fontWeight: 600, fontSize: '14px', color: '#212529' }}>
{senderName || 'Unknown'}
</span>
<span style={{ fontSize: '12px', color: '#6c757d' }}>
{formatTimestamp(createdAt)}
</span>
</div>
<div style={{ fontSize: '14px', color: '#212529', wordWrap: 'break-word' }}>
{text}
</div>
</div>
</div>
);
};
JKChatMessage.propTypes = {
message: PropTypes.shape({
id: PropTypes.string.isRequired,
senderId: PropTypes.string.isRequired,
senderName: PropTypes.string,
message: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired
}).isRequired
};
export default React.memo(JKChatMessage);