import { observer } from "mobx-react-lite"; import { useParams } from "react-router"; import { Link } from "react-router-dom"; import { User } from "revolt.js"; import { Channels, Message, Servers, Users } from "revolt.js/dist/api/objects"; import { ClientboundNotification } from "revolt.js/dist/websocket/notifications"; import { Text } from "preact-i18n"; import { useContext, useEffect, useState } from "preact/hooks"; import { Channel } from "../../../mobx"; import { useData } from "../../../mobx/State"; import { getState } from "../../../redux"; import { useIntermediate } from "../../../context/intermediate/Intermediate"; import { AppContext, ClientStatus, StatusContext, } from "../../../context/revoltjs/RevoltClient"; import { HookContext } from "../../../context/revoltjs/hooks"; import CollapsibleSection from "../../common/CollapsibleSection"; import Button from "../../ui/Button"; import Category from "../../ui/Category"; import InputBox from "../../ui/InputBox"; import Preloader from "../../ui/Preloader"; import placeholderSVG from "../items/placeholder.svg"; import { GenericSidebarBase, GenericSidebarList } from "../SidebarBase"; import { UserButton } from "../items/ButtonItem"; import { ChannelDebugInfo } from "./ChannelDebugInfo"; export default function MemberSidebar({ channel }: { channel?: Channel }) { switch (channel?.channel_type) { case "Group": return ; case "TextChannel": return ; default: return null; } } export const GroupMemberSidebar = observer( ({ channel }: { channel: Channel }) => { const { openScreen } = useIntermediate(); const store = useData(); const members = channel.recipients ?.map((member) => store.users.get(member)!) .filter((x) => typeof x !== "undefined"); /*const voice = useContext(VoiceContext); const voiceActive = voice.roomId === channel._id; let voiceParticipants: User[] = []; if (voiceActive) { const idArray = Array.from(voice.participants.keys()); voiceParticipants = idArray .map(x => users.find(y => y?._id === x)) .filter(x => typeof x !== "undefined") as User[]; members = members.filter(member => idArray.indexOf(member._id) === -1); voiceParticipants.sort((a, b) => a.username.localeCompare(b.username)); }*/ members?.sort((a, b) => { // ! FIXME: should probably rewrite all this code const l = +( (a.online && a.status?.presence !== Users.Presence.Invisible) ?? false ) | 0; const r = +( (b.online && b.status?.presence !== Users.Presence.Invisible) ?? false ) | 0; const n = r - l; if (n !== 0) { return n; } return a.username.localeCompare(b.username); }); return ( {/*voiceActive && voiceParticipants.length !== 0 && ( {" "} — {voiceParticipants.length} } /> {voiceParticipants.map( user => user && ( ) )} )*/} {" "} — {channel.recipients?.length ?? 0} } /> }> {members?.length === 0 && ( )} {members?.map( (user) => user && ( openScreen({ id: "profile", user_id: user._id, }) } /> ), )} ); }, ); export const ServerMemberSidebar = observer( ({ channel }: { channel: Channel }) => { const [members, setMembers] = useState( undefined, ); const store = useData(); const users = members ?.map((member) => store.users.get(member._id.user)!) .filter((x) => typeof x !== "undefined"); const { openScreen } = useIntermediate(); const status = useContext(StatusContext); const client = useContext(AppContext); useEffect(() => { if ( status === ClientStatus.ONLINE && typeof members === "undefined" ) { client.members .fetchMembers(channel.server!) .then((members) => setMembers(members)); } }, [status]); // ! FIXME: temporary code useEffect(() => { function onPacket(packet: ClientboundNotification) { if (!members) return; if (packet.type === "ServerMemberJoin") { if (packet.id !== channel.server) return; setMembers([ ...members, { _id: { server: packet.id, user: packet.user } }, ]); } else if (packet.type === "ServerMemberLeave") { if (packet.id !== channel.server) return; setMembers( members.filter( (x) => !( x._id.user === packet.user && x._id.server === packet.id ), ), ); } } client.addListener("packet", onPacket); return () => client.removeListener("packet", onPacket); }, [members]); // copy paste from above users?.sort((a, b) => { // ! FIXME: should probably rewrite all this code const l = +( (a.online && a.status?.presence !== Users.Presence.Invisible) ?? false ) | 0; const r = +( (b.online && b.status?.presence !== Users.Presence.Invisible) ?? false ) | 0; const n = r - l; if (n !== 0) { return n; } return a.username.localeCompare(b.username); }); return (
{!members && }
{members && ( —{" "} {users?.length ?? 0} }> {(users?.length ?? 0) === 0 && ( )} {users?.map( (user) => user && ( openScreen({ id: "profile", user_id: user._id, }) } /> ), )} )}
); }, ); function Search({ channel }: { channel: string }) { if (!getState().experiments.enabled?.includes("search")) return null; const client = useContext(AppContext); type Sort = "Relevance" | "Latest" | "Oldest"; const [sort, setSort] = useState("Relevance"); const [query, setV] = useState(""); const [results, setResults] = useState([]); async function search() { const data = await client.channels.searchWithUsers( channel, { query, sort }, true, ); setResults(data.messages); } return ( (BETA) }>
{["Relevance", "Latest", "Oldest"].map((key) => ( ))}
e.key === "Enter" && search()} value={query} onChange={(e) => setV(e.currentTarget.value)} />
{results.map((message) => { let href = ""; const channel = client.channels.get(message.channel); if (channel?.channel_type === "TextChannel") { href += `/server/${channel.server}`; } href += `/channel/${message.channel}/${message._id}`; return (
@ {client.users.get(message.author)?.username}
{message.content}
); })}
); }