2021-07-29 10:11:21 -04:00
|
|
|
import { observer } from "mobx-react-lite";
|
2021-07-10 10:57:29 -04:00
|
|
|
import { Link } from "react-router-dom";
|
2021-07-30 17:40:49 -04:00
|
|
|
import { Presence } from "revolt-api/types/Users";
|
|
|
|
import { Channel } from "revolt.js/dist/maps/Channels";
|
|
|
|
import Members, { Member } from "revolt.js/dist/maps/Members";
|
|
|
|
import { Message } from "revolt.js/dist/maps/Messages";
|
|
|
|
import { User } from "revolt.js/dist/maps/Users";
|
2021-07-05 06:23:23 -04:00
|
|
|
import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
|
|
|
|
|
2021-06-21 16:11:53 -04:00
|
|
|
import { Text } from "preact-i18n";
|
|
|
|
import { useContext, useEffect, useState } from "preact/hooks";
|
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
import { getState } from "../../../redux";
|
|
|
|
|
2021-07-02 08:35:50 -04:00
|
|
|
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
2021-07-05 06:23:23 -04:00
|
|
|
import {
|
2021-07-05 06:25:20 -04:00
|
|
|
AppContext,
|
|
|
|
ClientStatus,
|
|
|
|
StatusContext,
|
2021-07-30 17:40:49 -04:00
|
|
|
useClient,
|
2021-07-05 06:23:23 -04:00
|
|
|
} from "../../../context/revoltjs/RevoltClient";
|
2021-06-21 16:11:53 -04:00
|
|
|
|
2021-07-06 17:52:50 -04:00
|
|
|
import CollapsibleSection from "../../common/CollapsibleSection";
|
2021-07-21 13:27:05 -04:00
|
|
|
import Button from "../../ui/Button";
|
2021-07-05 06:23:23 -04:00
|
|
|
import Category from "../../ui/Category";
|
2021-07-10 10:57:29 -04:00
|
|
|
import InputBox from "../../ui/InputBox";
|
2021-07-05 05:59:48 -04:00
|
|
|
import Preloader from "../../ui/Preloader";
|
2021-07-05 06:23:23 -04:00
|
|
|
import placeholderSVG from "../items/placeholder.svg";
|
|
|
|
|
|
|
|
import { GenericSidebarBase, GenericSidebarList } from "../SidebarBase";
|
|
|
|
import { UserButton } from "../items/ButtonItem";
|
|
|
|
import { ChannelDebugInfo } from "./ChannelDebugInfo";
|
2021-06-21 16:11:53 -04:00
|
|
|
|
2021-07-29 13:41:01 -04:00
|
|
|
export default function MemberSidebar({ channel }: { channel?: Channel }) {
|
2021-07-05 06:25:20 -04:00
|
|
|
switch (channel?.channel_type) {
|
|
|
|
case "Group":
|
2021-07-29 13:41:01 -04:00
|
|
|
return <GroupMemberSidebar channel={channel} />;
|
2021-07-05 06:25:20 -04:00
|
|
|
case "TextChannel":
|
2021-07-29 13:41:01 -04:00
|
|
|
return <ServerMemberSidebar channel={channel} />;
|
2021-07-05 06:25:20 -04:00
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
2021-06-21 16:11:53 -04:00
|
|
|
}
|
|
|
|
|
2021-07-29 10:11:21 -04:00
|
|
|
export const GroupMemberSidebar = observer(
|
2021-07-29 13:41:01 -04:00
|
|
|
({ channel }: { channel: Channel }) => {
|
2021-07-29 10:11:21 -04:00
|
|
|
const { openScreen } = useIntermediate();
|
|
|
|
|
2021-07-30 17:40:49 -04:00
|
|
|
const client = useClient();
|
|
|
|
const members = channel.recipients?.filter(
|
|
|
|
(x) => typeof x !== "undefined",
|
|
|
|
);
|
2021-07-29 10:11:21 -04:00
|
|
|
|
|
|
|
/*const voice = useContext(VoiceContext);
|
2021-06-21 16:11:53 -04:00
|
|
|
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));
|
|
|
|
}*/
|
|
|
|
|
2021-07-29 13:41:01 -04:00
|
|
|
members?.sort((a, b) => {
|
2021-07-29 10:11:21 -04:00
|
|
|
// ! FIXME: should probably rewrite all this code
|
|
|
|
const l =
|
|
|
|
+(
|
2021-07-30 17:40:49 -04:00
|
|
|
(a!.online && a!.status?.presence !== Presence.Invisible) ??
|
2021-07-29 10:11:21 -04:00
|
|
|
false
|
|
|
|
) | 0;
|
|
|
|
const r =
|
|
|
|
+(
|
2021-07-30 17:40:49 -04:00
|
|
|
(b!.online && b!.status?.presence !== Presence.Invisible) ??
|
2021-07-29 10:11:21 -04:00
|
|
|
false
|
|
|
|
) | 0;
|
2021-06-21 16:11:53 -04:00
|
|
|
|
2021-07-29 10:11:21 -04:00
|
|
|
const n = r - l;
|
|
|
|
if (n !== 0) {
|
|
|
|
return n;
|
|
|
|
}
|
2021-07-09 09:34:36 -04:00
|
|
|
|
2021-07-30 17:40:49 -04:00
|
|
|
return a!.username.localeCompare(b!.username);
|
2021-07-29 10:11:21 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<GenericSidebarBase>
|
|
|
|
<GenericSidebarList>
|
|
|
|
<ChannelDebugInfo id={channel._id} />
|
2021-07-30 17:40:49 -04:00
|
|
|
<Search channel={channel} />
|
2021-07-29 10:11:21 -04:00
|
|
|
|
|
|
|
{/*voiceActive && voiceParticipants.length !== 0 && (
|
2021-06-21 16:11:53 -04:00
|
|
|
<Fragment>
|
|
|
|
<Category
|
|
|
|
type="members"
|
|
|
|
text={
|
|
|
|
<span>
|
|
|
|
<Text id="app.main.categories.participants" />{" "}
|
|
|
|
— {voiceParticipants.length}
|
|
|
|
</span>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
{voiceParticipants.map(
|
|
|
|
user =>
|
|
|
|
user && (
|
|
|
|
<LinkProfile user_id={user._id}>
|
|
|
|
<UserButton
|
|
|
|
key={user._id}
|
|
|
|
user={user}
|
|
|
|
context={channel}
|
|
|
|
/>
|
|
|
|
</LinkProfile>
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
</Fragment>
|
|
|
|
)*/}
|
2021-07-06 17:52:50 -04:00
|
|
|
<CollapsibleSection
|
2021-07-29 10:11:21 -04:00
|
|
|
sticky
|
2021-07-06 17:52:50 -04:00
|
|
|
id="members"
|
|
|
|
defaultValue
|
2021-07-10 10:57:29 -04:00
|
|
|
summary={
|
2021-07-29 10:11:21 -04:00
|
|
|
<Category
|
|
|
|
variant="uniform"
|
|
|
|
text={
|
|
|
|
<span>
|
|
|
|
<Text id="app.main.categories.members" />{" "}
|
2021-07-29 13:41:01 -04:00
|
|
|
— {channel.recipients?.length ?? 0}
|
2021-07-29 10:11:21 -04:00
|
|
|
</span>
|
|
|
|
}
|
|
|
|
/>
|
2021-07-10 10:57:29 -04:00
|
|
|
}>
|
2021-07-29 13:41:01 -04:00
|
|
|
{members?.length === 0 && (
|
2021-07-24 12:01:50 -04:00
|
|
|
<img src={placeholderSVG} loading="eager" />
|
|
|
|
)}
|
2021-07-29 13:41:01 -04:00
|
|
|
{members?.map(
|
2021-07-06 17:52:50 -04:00
|
|
|
(user) =>
|
|
|
|
user && (
|
|
|
|
<UserButton
|
|
|
|
key={user._id}
|
|
|
|
user={user}
|
2021-07-29 13:41:01 -04:00
|
|
|
context={channel!}
|
2021-07-06 17:52:50 -04:00
|
|
|
onClick={() =>
|
|
|
|
openScreen({
|
|
|
|
id: "profile",
|
|
|
|
user_id: user._id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
)}
|
|
|
|
</CollapsibleSection>
|
2021-07-29 10:11:21 -04:00
|
|
|
</GenericSidebarList>
|
|
|
|
</GenericSidebarBase>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
export const ServerMemberSidebar = observer(
|
2021-07-29 13:41:01 -04:00
|
|
|
({ channel }: { channel: Channel }) => {
|
2021-07-30 17:40:49 -04:00
|
|
|
const client = useClient();
|
2021-07-29 10:11:21 -04:00
|
|
|
const { openScreen } = useIntermediate();
|
|
|
|
const status = useContext(StatusContext);
|
|
|
|
|
|
|
|
useEffect(() => {
|
2021-07-30 17:40:49 -04:00
|
|
|
if (status === ClientStatus.ONLINE) {
|
|
|
|
channel.server!.fetchMembers();
|
2021-07-29 10:11:21 -04:00
|
|
|
}
|
|
|
|
}, [status]);
|
|
|
|
|
2021-07-30 17:40:49 -04:00
|
|
|
let users = [...client.members.keys()]
|
|
|
|
.filter((x) => x.server === channel.server_id)
|
|
|
|
.map((y) => client.users.get(y.user)!)
|
|
|
|
.filter((z) => typeof z !== "undefined");
|
2021-07-29 10:11:21 -04:00
|
|
|
|
|
|
|
// copy paste from above
|
2021-07-30 17:40:49 -04:00
|
|
|
users.sort((a, b) => {
|
2021-07-29 10:11:21 -04:00
|
|
|
// ! FIXME: should probably rewrite all this code
|
|
|
|
const l =
|
|
|
|
+(
|
2021-07-30 17:40:49 -04:00
|
|
|
(a.online && a.status?.presence !== Presence.Invisible) ??
|
2021-07-29 10:11:21 -04:00
|
|
|
false
|
|
|
|
) | 0;
|
|
|
|
const r =
|
|
|
|
+(
|
2021-07-30 17:40:49 -04:00
|
|
|
(b.online && b.status?.presence !== Presence.Invisible) ??
|
2021-07-29 10:11:21 -04:00
|
|
|
false
|
|
|
|
) | 0;
|
|
|
|
|
|
|
|
const n = r - l;
|
|
|
|
if (n !== 0) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.username.localeCompare(b.username);
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<GenericSidebarBase>
|
|
|
|
<GenericSidebarList>
|
|
|
|
<ChannelDebugInfo id={channel._id} />
|
2021-07-30 17:40:49 -04:00
|
|
|
<Search channel={channel} />
|
|
|
|
<div>{users.length === 0 && <Preloader type="ring" />}</div>
|
|
|
|
{users.length > 0 && (
|
2021-07-29 10:11:21 -04:00
|
|
|
<CollapsibleSection
|
|
|
|
//sticky //will re-add later, need to fix css
|
|
|
|
id="members"
|
|
|
|
defaultValue
|
|
|
|
summary={
|
|
|
|
<span>
|
|
|
|
<Text id="app.main.categories.members" /> —{" "}
|
|
|
|
{users?.length ?? 0}
|
|
|
|
</span>
|
|
|
|
}>
|
2021-07-30 17:40:49 -04:00
|
|
|
{users.map(
|
2021-07-29 10:11:21 -04:00
|
|
|
(user) =>
|
|
|
|
user && (
|
|
|
|
<UserButton
|
|
|
|
key={user._id}
|
|
|
|
user={user}
|
|
|
|
context={channel}
|
|
|
|
onClick={() =>
|
|
|
|
openScreen({
|
|
|
|
id: "profile",
|
|
|
|
user_id: user._id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
)}
|
|
|
|
</CollapsibleSection>
|
|
|
|
)}
|
|
|
|
</GenericSidebarList>
|
|
|
|
</GenericSidebarBase>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
2021-07-09 09:34:36 -04:00
|
|
|
|
2021-07-30 17:40:49 -04:00
|
|
|
function Search({ channel }: { channel: Channel }) {
|
2021-07-10 10:57:29 -04:00
|
|
|
if (!getState().experiments.enabled?.includes("search")) return null;
|
2021-07-09 09:34:36 -04:00
|
|
|
|
|
|
|
const client = useContext(AppContext);
|
2021-07-21 13:27:05 -04:00
|
|
|
type Sort = "Relevance" | "Latest" | "Oldest";
|
|
|
|
const [sort, setSort] = useState<Sort>("Relevance");
|
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
const [query, setV] = useState("");
|
|
|
|
const [results, setResults] = useState<Message[]>([]);
|
2021-07-09 09:34:36 -04:00
|
|
|
|
|
|
|
async function search() {
|
2021-07-30 17:40:49 -04:00
|
|
|
const data = await channel.searchWithUsers({ query, sort });
|
2021-07-09 09:34:36 -04:00
|
|
|
setResults(data.messages);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<CollapsibleSection
|
|
|
|
sticky
|
|
|
|
id="search"
|
|
|
|
defaultValue={false}
|
2021-07-21 13:27:05 -04:00
|
|
|
summary={
|
|
|
|
<>
|
|
|
|
<Text id="app.main.channel.search.title" /> (BETA)
|
|
|
|
</>
|
|
|
|
}>
|
|
|
|
<div style={{ display: "flex" }}>
|
|
|
|
{["Relevance", "Latest", "Oldest"].map((key) => (
|
|
|
|
<Button
|
|
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
|
|
compact
|
|
|
|
error={sort === key}
|
|
|
|
onClick={() => setSort(key as Sort)}>
|
|
|
|
<Text
|
|
|
|
id={`app.main.channel.search.sort.${key.toLowerCase()}`}
|
|
|
|
/>
|
|
|
|
</Button>
|
|
|
|
))}
|
|
|
|
</div>
|
2021-07-10 10:57:29 -04:00
|
|
|
<InputBox
|
|
|
|
style={{ width: "100%" }}
|
|
|
|
onKeyDown={(e) => e.key === "Enter" && search()}
|
|
|
|
value={query}
|
|
|
|
onChange={(e) => setV(e.currentTarget.value)}
|
|
|
|
/>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: "flex",
|
|
|
|
flexDirection: "column",
|
|
|
|
gap: "4px",
|
|
|
|
marginTop: "8px",
|
|
|
|
}}>
|
|
|
|
{results.map((message) => {
|
|
|
|
let href = "";
|
|
|
|
if (channel?.channel_type === "TextChannel") {
|
2021-07-09 09:34:36 -04:00
|
|
|
href += `/server/${channel.server}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
href += `/channel/${message.channel}/${message._id}`;
|
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
return (
|
|
|
|
<Link to={href}>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
margin: "2px",
|
|
|
|
padding: "6px",
|
|
|
|
background: "var(--primary-background)",
|
|
|
|
}}>
|
2021-07-30 17:40:49 -04:00
|
|
|
<b>@{message.author?.username}</b>
|
2021-07-10 10:57:29 -04:00
|
|
|
<br />
|
|
|
|
{message.content}
|
|
|
|
</div>
|
|
|
|
</Link>
|
|
|
|
);
|
|
|
|
})}
|
2021-07-09 09:34:36 -04:00
|
|
|
</div>
|
|
|
|
</CollapsibleSection>
|
2021-07-10 10:57:29 -04:00
|
|
|
);
|
2021-07-09 09:34:36 -04:00
|
|
|
}
|