2023-06-30 14:05:57 +00:00
|
|
|
/** @jsx h */
|
2023-12-22 10:20:37 +00:00
|
|
|
import { Component, h, VNode } from "https://esm.sh/preact@10.17.1";
|
2023-09-23 21:54:13 +00:00
|
|
|
import * as cl from "./conversation-list.tsx";
|
2023-12-22 07:51:08 +00:00
|
|
|
import { MessagePanel, NewMessageListener } from "./message-panel.tsx";
|
2023-10-04 21:34:43 +00:00
|
|
|
import { EventBus } from "../event-bus.ts";
|
2023-10-04 15:07:40 +00:00
|
|
|
import { CenterClass, IconButtonClass } from "./components/tw.ts";
|
2023-12-05 17:30:58 +00:00
|
|
|
import { ChatMessagesGetter, UI_Interaction_Event } from "./app_update.tsx";
|
2023-10-09 18:52:30 +00:00
|
|
|
import { NostrAccountContext, NostrEvent } from "../lib/nostr-ts/nostr.ts";
|
2023-11-03 13:09:13 +00:00
|
|
|
import { ConnectionPool } from "../lib/nostr-ts/relay-pool.ts";
|
2023-10-06 00:05:35 +00:00
|
|
|
import { ProfileSyncer } from "../features/profile.ts";
|
2023-06-30 14:05:57 +00:00
|
|
|
import { getFocusedContent } from "./app.tsx";
|
2023-07-05 09:32:02 +00:00
|
|
|
import { EventSyncer } from "./event_syncer.ts";
|
2023-10-04 15:07:40 +00:00
|
|
|
import { PrimaryTextColor } from "./style/colors.ts";
|
2023-11-11 11:19:21 +00:00
|
|
|
import { SettingIcon } from "./icons/setting-icon.tsx";
|
2023-10-09 18:39:52 +00:00
|
|
|
import { GroupMessageController } from "../features/gm.ts";
|
2023-10-06 00:05:35 +00:00
|
|
|
import { ProfileGetter } from "./search.tsx";
|
2023-10-07 17:15:27 +00:00
|
|
|
import { PublicKey } from "../lib/nostr-ts/key.ts";
|
2023-10-09 18:52:30 +00:00
|
|
|
import { EditorModel } from "./editor.tsx";
|
2023-10-19 03:44:43 +00:00
|
|
|
import { InviteButton } from "./invite-button.tsx";
|
2023-10-20 04:16:55 +00:00
|
|
|
import { IS_BETA_VERSION } from "./config.js";
|
2023-11-11 11:19:21 +00:00
|
|
|
import { UserIcon } from "./icons/user-icon.tsx";
|
|
|
|
import { LeftArrowIcon } from "./icons/left-arrow-icon.tsx";
|
2023-11-23 04:28:45 +00:00
|
|
|
import { RelayRecordGetter } from "../database.ts";
|
2023-12-22 07:51:08 +00:00
|
|
|
import { RightPanelModel } from "./right-panel.tsx";
|
2023-12-22 10:20:37 +00:00
|
|
|
import { Channel, PopChannel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
|
2023-10-09 18:52:30 +00:00
|
|
|
|
|
|
|
export type DM_Model = {
|
|
|
|
currentEditor: EditorModel | undefined;
|
2023-10-15 22:39:21 +00:00
|
|
|
focusedContent: Map<string, NostrEvent | PublicKey>;
|
2023-10-09 18:52:30 +00:00
|
|
|
isGroupMessage: boolean;
|
|
|
|
};
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
type DirectMessageContainerProps = {
|
|
|
|
rightPanelModel: RightPanelModel;
|
2023-10-04 21:34:43 +00:00
|
|
|
ctx: NostrAccountContext;
|
2023-06-30 14:05:57 +00:00
|
|
|
pool: ConnectionPool;
|
2023-10-04 21:34:43 +00:00
|
|
|
bus: EventBus<UI_Interaction_Event>;
|
2023-10-01 20:59:07 +00:00
|
|
|
profilesSyncer: ProfileSyncer;
|
2023-07-05 09:32:02 +00:00
|
|
|
eventSyncer: EventSyncer;
|
2023-10-09 18:39:52 +00:00
|
|
|
groupChatController: GroupMessageController;
|
2023-10-07 23:23:53 +00:00
|
|
|
// getters
|
|
|
|
profileGetter: ProfileGetter;
|
2023-11-20 09:14:17 +00:00
|
|
|
messageGetter: ChatMessagesGetter;
|
|
|
|
newMessageListener: NewMessageListener;
|
2023-10-07 23:23:53 +00:00
|
|
|
pinListGetter: cl.PinListGetter;
|
|
|
|
conversationLists: cl.ConversationListRetriever;
|
2023-10-07 20:40:18 +00:00
|
|
|
newMessageChecker: cl.NewMessageChecker;
|
2023-11-23 04:28:45 +00:00
|
|
|
relayRecordGetter: RelayRecordGetter;
|
2023-09-15 08:58:40 +00:00
|
|
|
} & DM_Model;
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-10-07 17:15:27 +00:00
|
|
|
export type StartInvite = {
|
|
|
|
type: "StartInvite";
|
|
|
|
publicKey: PublicKey;
|
|
|
|
};
|
|
|
|
|
2023-12-22 10:20:37 +00:00
|
|
|
type State = {
|
|
|
|
currentEditor: EditorModel | undefined;
|
|
|
|
};
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-12-22 10:20:37 +00:00
|
|
|
export class DirectMessageContainer extends Component<DirectMessageContainerProps, State> {
|
|
|
|
changes?: PopChannel<UI_Interaction_Event>;
|
|
|
|
|
|
|
|
state: State = {
|
|
|
|
currentEditor: undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
componentWillUpdate(nextProps: Readonly<DirectMessageContainerProps>): void {
|
|
|
|
this.setState({
|
|
|
|
currentEditor: nextProps.currentEditor,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async componentDidMount() {
|
|
|
|
this.setState({
|
|
|
|
currentEditor: this.props.currentEditor,
|
|
|
|
});
|
|
|
|
|
|
|
|
const changes = this.props.bus.onChange();
|
|
|
|
this.changes = changes;
|
|
|
|
for await (const change of changes) {
|
|
|
|
if (change.type == "SelectConversation") {
|
|
|
|
// todo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount(): void {
|
|
|
|
if (this.changes) {
|
|
|
|
this.changes.close();
|
|
|
|
}
|
|
|
|
}
|
2023-10-24 09:03:12 +00:00
|
|
|
|
2023-12-22 10:20:37 +00:00
|
|
|
render(props: DirectMessageContainerProps) {
|
|
|
|
const t = Date.now();
|
|
|
|
|
|
|
|
const currentEditor = props.currentEditor;
|
|
|
|
let buttons = [];
|
|
|
|
if (currentEditor && IS_BETA_VERSION) {
|
|
|
|
if (props.isGroupMessage) {
|
2023-10-20 09:07:41 +00:00
|
|
|
buttons.push(
|
2023-10-19 03:44:43 +00:00
|
|
|
<button
|
2023-12-18 10:23:15 +00:00
|
|
|
class={`w-8 h-8 ${CenterClass}`}
|
2023-10-19 03:44:43 +00:00
|
|
|
onClick={() => {
|
|
|
|
props.bus.emit({
|
2023-12-22 10:20:37 +00:00
|
|
|
type: "ViewUserDetail",
|
|
|
|
pubkey: currentEditor.pubkey,
|
2023-10-19 03:44:43 +00:00
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
2023-12-22 10:20:37 +00:00
|
|
|
<UserIcon
|
2023-12-18 10:23:15 +00:00
|
|
|
class={`w-6 h-6 text-[${PrimaryTextColor}] stroke-current`}
|
2023-10-19 03:44:43 +00:00
|
|
|
style={{ fill: "none" }}
|
|
|
|
/>
|
2023-10-20 09:07:41 +00:00
|
|
|
</button>,
|
|
|
|
);
|
2023-12-22 10:20:37 +00:00
|
|
|
|
|
|
|
const canEditGroupProfile = props.groupChatController.getGroupAdminCtx(currentEditor.pubkey);
|
|
|
|
if (canEditGroupProfile) {
|
|
|
|
buttons.push(
|
|
|
|
// setting button
|
|
|
|
<button
|
|
|
|
class={`w-8 h-8 ${CenterClass}`}
|
|
|
|
onClick={() => {
|
|
|
|
props.bus.emit({
|
|
|
|
type: "StartEditGroupChatProfile",
|
|
|
|
ctx: canEditGroupProfile,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<SettingIcon
|
|
|
|
class={`w-6 h-6 text-[${PrimaryTextColor}] stroke-current`}
|
|
|
|
style={{ fill: "none" }}
|
|
|
|
/>
|
|
|
|
</button>,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
buttons.push(
|
|
|
|
<InviteButton
|
|
|
|
groupChatController={props.groupChatController}
|
|
|
|
profileGetter={props.profileGetter}
|
|
|
|
userPublicKey={currentEditor.pubkey}
|
|
|
|
emit={props.bus.emit}
|
|
|
|
/>,
|
|
|
|
);
|
2023-10-20 09:07:41 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-22 10:20:37 +00:00
|
|
|
|
|
|
|
const vDom = (
|
|
|
|
<div
|
|
|
|
class={`h-full w-full flex bg-[#36393F] overflow-hidden`}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
class={`w-fit
|
|
|
|
max-sm:w-full
|
|
|
|
${props.currentEditor ? "max-sm:hidden" : ""}`}
|
|
|
|
>
|
|
|
|
<cl.ConversationList
|
|
|
|
eventBus={props.bus}
|
|
|
|
emit={props.bus.emit}
|
|
|
|
convoListRetriever={props.conversationLists}
|
|
|
|
groupChatListGetter={props.groupChatController}
|
|
|
|
hasNewMessages={props.newMessageChecker}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{this.state.currentEditor
|
|
|
|
? (
|
|
|
|
<div class={`flex flex-col flex-1 overflow-hidden`}>
|
|
|
|
<TopBar
|
|
|
|
bus={this.props.bus}
|
|
|
|
buttons={buttons}
|
|
|
|
currentEditor={this.state.currentEditor}
|
|
|
|
profileGetter={this.props.profileGetter}
|
|
|
|
showRightPanel={this.props.rightPanelModel.show}
|
|
|
|
/>
|
|
|
|
<div class={`flex-1 overflow-auto`}>
|
|
|
|
<MessagePanel
|
|
|
|
myPublicKey={props.ctx.publicKey}
|
|
|
|
rightPanelModel={props.rightPanelModel}
|
|
|
|
emit={props.bus.emit}
|
|
|
|
newMessageListener={props.newMessageListener}
|
|
|
|
focusedContent={getFocusedContent(
|
|
|
|
props.focusedContent.get(this.state.currentEditor.pubkey.hex),
|
|
|
|
props.profileGetter,
|
|
|
|
)}
|
|
|
|
profilesSyncer={props.profilesSyncer}
|
|
|
|
eventSyncer={props.eventSyncer}
|
|
|
|
isGroupMessage={props.isGroupMessage}
|
|
|
|
profileGetter={props.profileGetter}
|
|
|
|
editorModel={this.state.currentEditor}
|
|
|
|
messageGetter={props.messageGetter}
|
|
|
|
relayRecordGetter={props.relayRecordGetter}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
: undefined}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
console.debug("DirectMessageContainer:end", Date.now() - t);
|
|
|
|
return vDom;
|
2023-10-19 03:44:43 +00:00
|
|
|
}
|
2023-12-22 10:20:37 +00:00
|
|
|
}
|
2023-10-19 03:44:43 +00:00
|
|
|
|
2023-12-22 10:20:37 +00:00
|
|
|
function TopBar(props: {
|
|
|
|
bus: EventBus<UI_Interaction_Event>;
|
|
|
|
currentEditor: EditorModel;
|
|
|
|
profileGetter: ProfileGetter;
|
|
|
|
showRightPanel: boolean;
|
|
|
|
buttons: VNode[];
|
|
|
|
}) {
|
|
|
|
return (
|
2023-06-30 14:05:57 +00:00
|
|
|
<div
|
2023-12-22 10:20:37 +00:00
|
|
|
class={`h-14 border-l border-b border-[#36393F] flex
|
|
|
|
items-center justify-between bg-[#2F3136]`}
|
2023-06-30 14:05:57 +00:00
|
|
|
>
|
2023-12-22 10:20:37 +00:00
|
|
|
<div class={`flex items-center overflow-hidden`}>
|
|
|
|
<button
|
|
|
|
onClick={() => {
|
|
|
|
props.bus.emit({
|
|
|
|
type: "BackToContactList",
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
class={`w-6 h-6 mobile:mr-2 desktop:hidden ${IconButtonClass}`}
|
|
|
|
>
|
|
|
|
<LeftArrowIcon
|
|
|
|
class={`w-4 h-4`}
|
|
|
|
style={{
|
|
|
|
fill: "rgb(185, 187, 190)",
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</button>
|
|
|
|
<span
|
|
|
|
// https://tailwindcss.com/docs/customizing-colors
|
|
|
|
// https://tailwindcss.com/docs/cursor
|
|
|
|
class={`text-[#F3F4EA] text-[1.2rem]
|
2023-12-05 17:30:58 +00:00
|
|
|
hover:text-[#60a5fa] hover:cursor-pointer
|
|
|
|
ml-4 mobile:text-base whitespace-nowrap truncate`}
|
2023-12-22 10:20:37 +00:00
|
|
|
onClick={() => {
|
|
|
|
if (!props.currentEditor) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
props.bus.emit({
|
|
|
|
type: "ViewUserDetail",
|
|
|
|
pubkey: props.currentEditor.pubkey,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{props.profileGetter.getProfilesByPublicKey(
|
|
|
|
props.currentEditor.pubkey,
|
|
|
|
)
|
|
|
|
?.profile.name ||
|
|
|
|
props.currentEditor.pubkey.bech32()}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{props.buttons}
|
|
|
|
|
|
|
|
{!props.showRightPanel
|
|
|
|
? (
|
|
|
|
<button
|
|
|
|
class={`absolute z-10 w-6 h-6 transition-transform duration-100 ease-in-out right-4 mobile:right-0 top-4${
|
|
|
|
props.showRightPanel ? " rotate-180" : ""
|
|
|
|
} ${IconButtonClass}`}
|
|
|
|
onClick={() => {
|
|
|
|
props.bus.emit({
|
|
|
|
type: "ToggleRightPanel",
|
|
|
|
show: !props.showRightPanel,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<LeftArrowIcon
|
|
|
|
class={`w-4 h-4`}
|
|
|
|
style={{
|
|
|
|
fill: "#F3F4EA",
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</button>
|
|
|
|
)
|
|
|
|
: undefined}
|
|
|
|
</div>
|
2023-06-30 14:05:57 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|