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:
parent
7264fcb8ee
commit
a78d2bc52f
|
|
@ -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);
|
||||
Loading…
Reference in New Issue