DM styles update
This commit is contained in:
@ -1,12 +1,14 @@
|
||||
import "./MessagesPage.css";
|
||||
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { TLVEntryType, decodeTLV } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import { useUserProfile, useUserSearch } from "@snort/system-react";
|
||||
|
||||
import UnreadCount from "Element/UnreadCount";
|
||||
import ProfileImage, { getDisplayName } from "Element/ProfileImage";
|
||||
import { parseId } from "SnortUtils";
|
||||
import { appendDedupe, debounce, parseId } from "SnortUtils";
|
||||
import NoteToSelf from "Element/NoteToSelf";
|
||||
import useModeration from "Hooks/useModeration";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
@ -16,11 +18,9 @@ import DmWindow from "Element/DmWindow";
|
||||
import Avatar from "Element/Avatar";
|
||||
import Icon from "Icons/Icon";
|
||||
import Text from "Element/Text";
|
||||
import { System } from "index";
|
||||
import { Chat, ChatType, useChatSystem } from "chat";
|
||||
|
||||
import "./MessagesPage.css";
|
||||
import messages from "./messages";
|
||||
import { Chat, ChatType, createChatLink, useChatSystem } from "chat";
|
||||
import Modal from "Element/Modal";
|
||||
import ProfilePreview from "Element/ProfilePreview";
|
||||
|
||||
const TwoCol = 768;
|
||||
const ThreeCol = 1500;
|
||||
@ -49,15 +49,15 @@ export default function MessagesPage() {
|
||||
|
||||
function noteToSelf(chat: Chat) {
|
||||
return (
|
||||
<div className="flex mb10" key={chat.id} onClick={e => openChat(e, chat.type, chat.id)}>
|
||||
<div className="flex p" key={chat.id} onClick={e => openChat(e, chat.type, chat.id)}>
|
||||
<NoteToSelf clickable={true} className="f-grow" link="" pubkey={chat.id} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function conversationIdent(chat: Chat) {
|
||||
if (chat.participants.length === 1) {
|
||||
const p = chat.participants[0];
|
||||
function conversationIdent(cx: Chat) {
|
||||
if (cx.participants.length === 1) {
|
||||
const p = cx.participants[0];
|
||||
|
||||
if (p.type === "pubkey") {
|
||||
return <ProfileImage pubkey={p.id} className="f-grow" link="" />;
|
||||
@ -67,27 +67,29 @@ export default function MessagesPage() {
|
||||
} else {
|
||||
return (
|
||||
<div className="flex f-grow pfp-overlap">
|
||||
{chat.participants.map(v => (
|
||||
{cx.participants.map(v => (
|
||||
<ProfileImage pubkey={v.id} link="" showUsername={false} />
|
||||
))}
|
||||
<div className="f-grow">{chat.title}</div>
|
||||
{cx.title ?? <FormattedMessage defaultMessage="Group Chat" />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function conversation(chat: Chat) {
|
||||
function conversation(cx: Chat) {
|
||||
if (!login.publicKey) return null;
|
||||
const participants = chat.participants.map(a => a.id);
|
||||
if (participants.length === 1 && participants[0] === login.publicKey) return noteToSelf(chat);
|
||||
const participants = cx.participants.map(a => a.id);
|
||||
if (participants.length === 1 && participants[0] === login.publicKey) return noteToSelf(cx);
|
||||
|
||||
const isActive = cx.id === chat;
|
||||
return (
|
||||
<div className="flex mb10" key={chat.id} onClick={e => openChat(e, chat.type, chat.id)}>
|
||||
{conversationIdent(chat)}
|
||||
<div className={`flex p${isActive ? " active" : ""}`} key={cx.id} onClick={e => openChat(e, cx.type, cx.id)}>
|
||||
{conversationIdent(cx)}
|
||||
<div className="nowrap">
|
||||
<small>
|
||||
<NoteTime from={chat.lastMessage * 1000} fallback={formatMessage({ defaultMessage: "Just now" })} />
|
||||
<NoteTime from={cx.lastMessage * 1000} fallback={formatMessage({ defaultMessage: "Just now" })} />
|
||||
</small>
|
||||
{chat.unread > 0 && <UnreadCount unread={chat.unread} />}
|
||||
{cx.unread > 0 && <UnreadCount unread={cx.unread} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -96,14 +98,12 @@ export default function MessagesPage() {
|
||||
return (
|
||||
<div className="dm-page">
|
||||
{(pageWidth >= TwoCol || !chat) && (
|
||||
<div>
|
||||
<div className="flex">
|
||||
<h3 className="f-grow">
|
||||
<FormattedMessage {...messages.Messages} />
|
||||
</h3>
|
||||
<div className="chat-list">
|
||||
<div className="flex p f-space">
|
||||
<button disabled={unreadCount <= 0} type="button">
|
||||
<FormattedMessage {...messages.MarkAllRead} />
|
||||
<FormattedMessage defaultMessage="Mark all read" />
|
||||
</button>
|
||||
<NewChatWindow />
|
||||
</div>
|
||||
{chats
|
||||
.sort((a, b) => {
|
||||
@ -117,7 +117,7 @@ export default function MessagesPage() {
|
||||
.map(conversation)}
|
||||
</div>
|
||||
)}
|
||||
{chat && <DmWindow id={chat} />}
|
||||
{chat ? <DmWindow id={chat} /> : pageWidth >= TwoCol && <div></div>}
|
||||
{pageWidth >= ThreeCol && chat && (
|
||||
<div>
|
||||
<ProfileDmActions id={chat} />
|
||||
@ -132,7 +132,7 @@ function ProfileDmActions({ id }: { id: string }) {
|
||||
.filter(a => a.type === TLVEntryType.Author)
|
||||
.map(a => a.value as string);
|
||||
const pubkey = authors[0];
|
||||
const profile = useUserProfile(System, pubkey);
|
||||
const profile = useUserProfile(pubkey);
|
||||
const { block, unblock, isBlocked } = useModeration();
|
||||
|
||||
function truncAbout(s?: string) {
|
||||
@ -158,3 +158,105 @@ function ProfileDmActions({ id }: { id: string }) {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function NewChatWindow() {
|
||||
const [show, setShow] = useState(false);
|
||||
const [newChat, setNewChat] = useState<string[]>([]);
|
||||
const [results, setResults] = useState<string[]>([]);
|
||||
const [term, setSearchTerm] = useState("");
|
||||
const navigate = useNavigate();
|
||||
const search = useUserSearch();
|
||||
const { follows } = useLogin();
|
||||
|
||||
useEffect(() => {
|
||||
setNewChat([]);
|
||||
setSearchTerm("");
|
||||
setResults(follows.item);
|
||||
}, [show]);
|
||||
|
||||
useEffect(() => {
|
||||
return debounce(500, () => {
|
||||
if (term) {
|
||||
search(term).then(setResults);
|
||||
} else {
|
||||
setResults(follows.item);
|
||||
}
|
||||
});
|
||||
}, [term]);
|
||||
|
||||
function togglePubkey(a: string) {
|
||||
setNewChat(c => (c.includes(a) ? c.filter(v => v !== a) : appendDedupe(c, [a])));
|
||||
}
|
||||
|
||||
function startChat() {
|
||||
setShow(false);
|
||||
if (newChat.length === 1) {
|
||||
navigate(createChatLink(ChatType.DirectMessage, newChat[0]));
|
||||
} else {
|
||||
navigate(createChatLink(ChatType.PrivateGroupChat, ...newChat));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button type="button" className="new-chat" onClick={() => setShow(true)}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
{show && (
|
||||
<Modal onClose={() => setShow(false)} className="new-chat-modal">
|
||||
<div className="flex-column g16">
|
||||
<div className="flex f-space">
|
||||
<h2>
|
||||
<FormattedMessage defaultMessage="New Chat" />
|
||||
</h2>
|
||||
<button onClick={startChat}>
|
||||
<FormattedMessage defaultMessage="Start chat" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex-column g8">
|
||||
<h3>
|
||||
<FormattedMessage defaultMessage="Search users" />
|
||||
</h3>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="npub/nprofile/nostr address"
|
||||
value={term}
|
||||
onChange={e => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex">
|
||||
{newChat.map(a => (
|
||||
<ProfileImage
|
||||
key={`selected-${a}`}
|
||||
pubkey={a}
|
||||
showUsername={false}
|
||||
link=""
|
||||
onClick={() => togglePubkey(a)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage defaultMessage="People you follow" />
|
||||
</p>
|
||||
<div className="user-list flex-column g2">
|
||||
{results.map(a => {
|
||||
return (
|
||||
<ProfilePreview
|
||||
pubkey={a}
|
||||
key={`option-${a}`}
|
||||
options={{ about: false, linkToProfile: false }}
|
||||
actions={<></>}
|
||||
onClick={() => togglePubkey(a)}
|
||||
className={newChat.includes(a) ? "active" : undefined}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user