ttrpg-tools/src/components/journal/ComposePanel.tsx

88 lines
2.4 KiB
TypeScript

/**
* ComposePanel — type picker + dynamic form + send button
*/
import { Component, createSignal, For, Show, createMemo } from "solid-js";
import { registeredTypes, canEmit } from "./registry";
import { sendMessage, useJournalStream } from "../stores/journalStream";
import type { MessageTypeDef } from "./registry";
import { DynamicForm } from "./DynamicForm";
export const ComposePanel: Component = () => {
const stream = useJournalStream();
const [selectedType, setSelectedType] = createSignal<string>("chat");
const [formData, setFormData] = createSignal<Record<string, unknown>>({});
const [error, setError] = createSignal<string | null>(null);
const [sending, setSending] = createSignal(false);
const role = () => stream.myRole;
// Available types filtered by role
const availableTypes = createMemo(() => {
const types: string[] = [];
for (const type of registeredTypes()) {
if (canEmit(type, role())) {
types.push(type);
}
}
// Default to chat if available, otherwise first
if (types.includes("chat")) {
return types;
}
return types;
});
const handleSend = () => {
setError(null);
setSending(true);
const result = sendMessage(selectedType(), formData());
if (!result.success) {
setError(result.error);
} else {
setFormData({}); // Reset on success
}
setSending(false);
};
return (
<div class="border-t border-gray-200 p-2 space-y-2 bg-white">
{/* Type picker */}
<div class="flex items-center gap-2">
<select
value={selectedType()}
onChange={(e) => {
setSelectedType(e.currentTarget.value);
setFormData({});
}}
class="text-xs border border-gray-300 rounded px-2 py-1 bg-white"
>
<For each={availableTypes()}>
{(type) => <option value={type}>{type}</option>}
</For>
</select>
<button
onClick={handleSend}
disabled={sending()}
class="ml-auto bg-blue-600 text-white rounded px-3 py-1 text-xs hover:bg-blue-700 disabled:opacity-50"
>
{sending() ? "..." : "发送"}
</button>
</div>
{/* Dynamic form */}
<DynamicForm
type={selectedType()}
value={formData()}
onChange={setFormData}
/>
<Show when={error()}>
<p class="text-red-500 text-xs">{error()}</p>
</Show>
</div>
);
};