- 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
112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
import { createSignal } from 'solid-js';
|
|
import { gql } from '@urql/core';
|
|
import { createMutation } from '@urql/solid';
|
|
|
|
const CREATE_ROOM_MUTATION = gql`
|
|
mutation CreateRoom(
|
|
$name: String!
|
|
$description: String
|
|
$isPrivate: Boolean
|
|
) {
|
|
createRoom(name: $name, description: $description, isPrivate: $isPrivate) {
|
|
id
|
|
name
|
|
description
|
|
isPrivate
|
|
}
|
|
}
|
|
`;
|
|
|
|
interface CreateRoomProps {
|
|
onRoomCreated: (roomId: string) => void;
|
|
}
|
|
|
|
export function CreateRoom(props: CreateRoomProps) {
|
|
const [name, setName] = createSignal('');
|
|
const [description, setDescription] = createSignal('');
|
|
const [isPrivate, setIsPrivate] = createSignal(false);
|
|
const [error, setError] = createSignal('');
|
|
const [isOpen, setIsOpen] = createSignal(false);
|
|
|
|
const [state, executeMutation] = createMutation(CREATE_ROOM_MUTATION);
|
|
|
|
const handleSubmit = async (e: Event) => {
|
|
e.preventDefault();
|
|
|
|
if (!name().trim()) {
|
|
setError('Room name is required');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const result = await executeMutation({
|
|
name: name(),
|
|
description: description(),
|
|
isPrivate: isPrivate(),
|
|
});
|
|
|
|
if (result.error) {
|
|
setError(result.error.message);
|
|
return;
|
|
}
|
|
|
|
if (result.data?.createRoom) {
|
|
setName('');
|
|
setDescription('');
|
|
setIsPrivate(false);
|
|
setIsOpen(false);
|
|
props.onRoomCreated(result.data.createRoom.id);
|
|
}
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'An error occurred');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div class='create-room'>
|
|
<button class='create-room-button' onClick={() => setIsOpen(!isOpen())}>
|
|
{isOpen() ? 'Cancel' : 'Create Room'}
|
|
</button>
|
|
|
|
{isOpen() && (
|
|
<div class='create-room-form'>
|
|
<h3>Create a New Room</h3>
|
|
{error() && <div class='error'>{error()}</div>}
|
|
<form onSubmit={handleSubmit}>
|
|
<div class='form-group'>
|
|
<label for='room-name'>Room Name</label>
|
|
<input
|
|
type='text'
|
|
id='room-name'
|
|
value={name()}
|
|
onInput={(e) => setName(e.currentTarget.value)}
|
|
required
|
|
/>
|
|
</div>
|
|
<div class='form-group'>
|
|
<label for='room-description'>Description (optional)</label>
|
|
<textarea
|
|
id='room-description'
|
|
value={description()}
|
|
onInput={(e) => setDescription(e.currentTarget.value)}
|
|
/>
|
|
</div>
|
|
<div class='form-group checkbox'>
|
|
<label>
|
|
<input
|
|
type='checkbox'
|
|
checked={isPrivate()}
|
|
onChange={(e) => setIsPrivate(e.currentTarget.checked)}
|
|
/>
|
|
Private Room
|
|
</label>
|
|
</div>
|
|
<button type='submit' disabled={state.fetching}>
|
|
{state.fetching ? 'Creating...' : 'Create Room'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|