blowater/app/UI/public-message-container.tsx

151 lines
5.0 KiB
TypeScript

import { Component, h } from "https://esm.sh/preact@10.17.1";
import { SingleRelayConnection } from "../../libs/nostr.ts/relay-single.ts";
import { emitFunc, EventBus } from "../event-bus.ts";
import { UI_Interaction_Event } from "./app_update.tsx";
import { setState } from "./_helper.ts";
import { ProfileGetter } from "./search.tsx";
import { RelayRecordGetter } from "../database.ts";
import { NewMessageChecker } from "./conversation-list.tsx";
import { ConversationListRetriever } from "./conversation-list.tsx";
import { NostrAccountContext } from "../../libs/nostr.ts/nostr.ts";
import { MessagePanel } from "./message-panel.tsx";
import { PublicKey } from "../../libs/nostr.ts/key.ts";
import { ChatMessage } from "./message.ts";
import { func_GetEventByID } from "./message-list.tsx";
import { Filter, FilterContent } from "./filter.tsx";
import { NoteID } from "../../libs/nostr.ts/nip19.ts";
export type Public_Model = {
relaySelectedChannel: Map<string, /* relay url */ string /* channel name */>;
};
export type func_IsUserBlocked = (pubkey: PublicKey) => boolean;
type Props = {
ctx: NostrAccountContext;
relay: SingleRelayConnection;
bus: EventBus<UI_Interaction_Event>;
messages: ChatMessage[];
getters: {
profileGetter: ProfileGetter;
convoListRetriever: ConversationListRetriever;
newMessageChecker: NewMessageChecker;
relayRecordGetter: RelayRecordGetter;
isUserBlocked: func_IsUserBlocked;
getEventByID: func_GetEventByID;
};
} & Public_Model;
type State = {
currentSelectedChannel: string /*channel name*/ | undefined;
currentEditor: {
text: string;
};
filter: FilterContent | undefined;
};
export class PublicMessageContainer extends Component<Props, State> {
state: State = {
currentSelectedChannel: "general",
currentEditor: {
text: "",
},
filter: undefined,
};
async componentDidMount() {
for await (const e of this.props.bus.onChange()) {
if (e.type == "FilterContent") {
await setState(this, {
filter: e,
});
}
}
}
render(props: Props, state: State) {
let msgs = props.messages;
const filter = this.state.filter;
if (filter) {
msgs = filter_messages(this.props.messages, filter);
}
return (
<div class="flex flex-row h-full w-full flex bg-[#36393F] overflow-hidden">
{this.state.currentSelectedChannel
? (
<div class={`flex flex-col flex-1 overflow-hidden`}>
<TopBar
currentSelected={state.currentSelectedChannel}
emit={props.bus.emit}
/>
<div class={`flex-1 overflow-auto`}>
{
<MessagePanel
key={props.relay.url}
myPublicKey={props.ctx.publicKey}
emit={props.bus.emit}
eventSub={props.bus}
getters={props.getters}
messages={msgs}
/>
}
</div>
</div>
)
: undefined}
</div>
);
}
}
function TopBar(props: {
currentSelected: string | undefined;
emit: emitFunc<FilterContent>;
}) {
return (
<div
class={`h-14 border-l border-b border-[#36393F] flex
items-center justify-between bg-[#2F3136]`}
>
<div class={`flex items-center overflow-hidden`}>
<span
class={`text-[#F3F4EA] text-[1.2rem] mx-4
whitespace-nowrap truncate`}
>
{props.currentSelected}
</span>
<div>
<Filter {...props}></Filter>
</div>
</div>
</div>
);
}
function filter_messages(msgs: ChatMessage[], filter: FilterContent) {
const filter_string = filter.content.trim().toLocaleLowerCase();
const pubkey = PublicKey.FromBech32(filter_string);
const is_pubkey = pubkey instanceof PublicKey;
const noteID = NoteID.FromBech32(filter_string);
const is_note = noteID instanceof NoteID;
msgs = msgs.filter((msg) => {
if (is_pubkey) {
if (msg.author.hex == pubkey.hex) {
return true;
}
}
if (is_note) {
if (msg.event.id == noteID.hex) {
return true;
}
}
if (msg.content.toLocaleLowerCase().indexOf(filter_string) != -1) {
return true;
}
return false;
});
return msgs;
}