refactor: migrate from Next.js to SolidJS and GraphQL
- Converted web application from Next.js to SolidJS with Vite - Replaced React components with SolidJS components - Implemented GraphQL client using URQL - Added authentication, room, and chat components - Updated project structure and configuration files - Removed unnecessary Next.js and docs-related files - Added Docker support for web and API applications
This commit is contained in:
parent
8f3aa2fc26
commit
16731409df
81 changed files with 13585 additions and 1163 deletions
176
apps/web/src/components/chat-room.tsx
Normal file
176
apps/web/src/components/chat-room.tsx
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import { createSignal, createEffect, For, Show } from 'solid-js';
|
||||
import { gql } from '@urql/core';
|
||||
import { createQuery, createMutation, createSubscription } from '@urql/solid';
|
||||
import { Message, Room } from '../types';
|
||||
|
||||
const ROOM_QUERY = gql`
|
||||
query GetRoom($id: ID!) {
|
||||
room(id: $id) {
|
||||
id
|
||||
name
|
||||
description
|
||||
isPrivate
|
||||
owner {
|
||||
id
|
||||
username
|
||||
}
|
||||
members {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MESSAGES_QUERY = gql`
|
||||
query GetMessages($roomId: ID!) {
|
||||
messages(roomId: $roomId) {
|
||||
id
|
||||
content
|
||||
createdAt
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const SEND_MESSAGE_MUTATION = gql`
|
||||
mutation SendMessage($content: String!, $roomId: ID!) {
|
||||
sendMessage(content: $content, roomId: $roomId) {
|
||||
id
|
||||
content
|
||||
createdAt
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MESSAGE_SUBSCRIPTION = gql`
|
||||
subscription OnMessageAdded($roomId: ID!) {
|
||||
messageAdded(roomId: $roomId) {
|
||||
id
|
||||
content
|
||||
createdAt
|
||||
user {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface ChatRoomProps {
|
||||
roomId: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export function ChatRoom(props: ChatRoomProps) {
|
||||
const [message, setMessage] = createSignal('');
|
||||
const [messages, setMessages] = createSignal<Message[]>([]);
|
||||
|
||||
// Query room details
|
||||
const [roomQuery] = createQuery({
|
||||
query: ROOM_QUERY,
|
||||
variables: { id: props.roomId },
|
||||
});
|
||||
|
||||
// Query messages
|
||||
const [messagesQuery] = createQuery({
|
||||
query: MESSAGES_QUERY,
|
||||
variables: { roomId: props.roomId },
|
||||
});
|
||||
|
||||
// Send message mutation
|
||||
const [, sendMessage] = createMutation(SEND_MESSAGE_MUTATION);
|
||||
|
||||
// Subscribe to new messages
|
||||
const [messageSubscription] = createSubscription({
|
||||
query: MESSAGE_SUBSCRIPTION,
|
||||
variables: { roomId: props.roomId },
|
||||
});
|
||||
|
||||
// Load initial messages
|
||||
createEffect(() => {
|
||||
const result = messagesQuery;
|
||||
if (result.data?.messages) {
|
||||
setMessages(result.data.messages);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle new messages from subscription
|
||||
createEffect(() => {
|
||||
const result = messageSubscription;
|
||||
if (result.data?.messageAdded) {
|
||||
const newMessage = result.data.messageAdded;
|
||||
setMessages((prev) => [...prev, newMessage]);
|
||||
}
|
||||
});
|
||||
|
||||
const handleSendMessage = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!message().trim()) return;
|
||||
|
||||
try {
|
||||
await sendMessage({
|
||||
content: message(),
|
||||
roomId: props.roomId,
|
||||
});
|
||||
setMessage('');
|
||||
} catch (error) {
|
||||
console.error('Failed to send message:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const formatTime = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
};
|
||||
|
||||
return (
|
||||
<div class='chat-room'>
|
||||
<Show when={roomQuery.data?.room} fallback={<div>Loading room...</div>}>
|
||||
<div class='chat-header'>
|
||||
<h2>{roomQuery.data?.room.name}</h2>
|
||||
<p>{roomQuery.data?.room.description}</p>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class='chat-messages'>
|
||||
<Show
|
||||
when={!roomQuery.fetching}
|
||||
fallback={<div>Loading messages...</div>}
|
||||
>
|
||||
<For each={messages()}>
|
||||
{(message) => (
|
||||
<div
|
||||
class={`message ${message.user.id === props.userId ? 'own-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>
|
||||
)}
|
||||
</For>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<form class='message-form' onSubmit={handleSendMessage}>
|
||||
<input
|
||||
type='text'
|
||||
value={message()}
|
||||
onInput={(e) => setMessage(e.currentTarget.value)}
|
||||
placeholder='Type a message...'
|
||||
/>
|
||||
<button type='submit'>Send</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue