feat: enhance chat room UI with user avatars and message improvements

- Added user avatar generation with external avatar service
- Implemented message styling with user-specific layouts
- Added message length counter and validation
- Updated CSS for improved message and user profile display
- Restricted message length to 2048 characters
- Added disabled state for send button based on message length
This commit is contained in:
Juan Sebastián Montoya 2025-03-07 01:06:31 -05:00
parent 3d41e2cc42
commit d4d99fb5e7
5 changed files with 144 additions and 24 deletions

View file

@ -161,14 +161,18 @@ export function ChatRoom(props: ChatRoomProps) {
}
});
const MAX_MESSAGE_LENGTH = 2048;
const handleSendMessage = async (e: Event) => {
e.preventDefault();
if (!message().trim()) return;
const trimmedMessage = message().trim();
if (!trimmedMessage) return;
if (trimmedMessage.length > MAX_MESSAGE_LENGTH) return;
try {
await sendMessage({
content: message(),
content: trimmedMessage,
roomId: props.roomId,
});
setMessage('');
@ -242,6 +246,10 @@ export function ChatRoom(props: ChatRoomProps) {
};
});
// Function to generate avatar URL
const getUserAvatarUrl = (userId: string, size: number = 40) =>
`https://avatars.jusemon.com/${userId}?size=${size}`;
return (
<div class='chat-room'>
<Show when={roomQuery.data?.room} fallback={<div>Loading room...</div>}>
@ -276,13 +284,24 @@ export function ChatRoom(props: ChatRoomProps) {
<For each={messages()}>
{(message) => (
<div
class={`message ${message.user.id === props.userId ? 'own-message' : ''}`}
class={`message-wrapper ${message.user.id === props.userId ? 'own-message-wrapper' : 'other-message-wrapper'}`}
>
<div class='message-header'>
<span class='username'>{message.user.username}</span>
<span class='time'>{formatTime(message.createdAt)}</span>
{message.user.id !== props.userId && (
<img
src={getUserAvatarUrl(message.user.id)}
alt={`${message.user.username}'s avatar`}
class='message-avatar'
/>
)}
<div
class={`message ${message.user.id === props.userId ? 'own-message' : 'other-message'}`}
>
<div class='message-header'>
<span class='username'>{message.user.username}</span>
<span class='time'>{formatTime(message.createdAt)}</span>
</div>
<div class='message-content'>{message.content}</div>
</div>
<div class='message-content'>{message.content}</div>
</div>
)}
</For>
@ -295,7 +314,12 @@ export function ChatRoom(props: ChatRoomProps) {
ref={messageInput}
type='text'
value={message()}
onInput={(e) => setMessage(e.currentTarget.value)}
onInput={(e) => {
const inputValue = e.currentTarget.value;
if (inputValue.length <= MAX_MESSAGE_LENGTH) {
setMessage(inputValue);
}
}}
placeholder='Type a message...'
/>
<button
@ -306,7 +330,18 @@ export function ChatRoom(props: ChatRoomProps) {
😊
</button>
</div>
<button type='submit'>Send</button>
<div class='message-length-counter'>
{message().length}/{MAX_MESSAGE_LENGTH}
</div>
<button
type='submit'
disabled={
message().trim().length === 0 ||
message().length > MAX_MESSAGE_LENGTH
}
>
Send
</button>
{showEmojiPicker() && (
<div ref={emojiPickerContainer} class='emoji-picker-container'>