88 lines
2.4 KiB
TypeScript
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>
|
|
);
|
|
};
|