revite/src/components/navigation/right/MemberSidebar.tsx

321 lines
12 KiB
TypeScript
Raw Normal View History

2021-08-05 09:47:00 -04:00
/* eslint-disable react-hooks/rules-of-hooks */
2021-07-29 10:11:21 -04:00
import { observer } from "mobx-react-lite";
import { Link, useParams } 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 { Message } from "revolt.js/dist/maps/Messages";
2021-07-05 06:23:23 -04:00
import { Text } from "preact-i18n";
import { useContext, useEffect, useState } from "preact/hooks";
import { getState } from "../../../redux";
import { useIntermediate } from "../../../context/intermediate/Intermediate";
2021-07-05 06:23:23 -04:00
import {
2021-07-05 06:25:20 -04:00
ClientStatus,
StatusContext,
2021-07-30 17:40:49 -04:00
useClient,
2021-07-05 06:23:23 -04:00
} from "../../../context/revoltjs/RevoltClient";
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";
import InputBox from "../../ui/InputBox";
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";
export default function MemberSidebar({ channel: obj }: { channel?: Channel }) {
const { channel: channel_id } = useParams<{ channel: string }>();
const client = useClient();
const channel = obj ?? client.channels.get(channel_id);
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-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 members = channel.recipients?.filter(
(x) => typeof x !== "undefined",
);
2021-07-29 10:11:21 -04:00
/*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));
}*/
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-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>
2021-08-07 15:43:08 -04:00
<ChannelDebugInfo channel={channel} />
2021-07-30 17:40:49 -04:00
<Search channel={channel} />
2021-07-29 10:11:21 -04:00
{/*voiceActive && voiceParticipants.length !== 0 && (
<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>
)*/}
<CollapsibleSection
2021-07-29 10:11:21 -04:00
sticky
id="members"
defaultValue
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-29 13:41:01 -04:00
{members?.length === 0 && (
<img src={placeholderSVG} loading="eager" />
)}
2021-07-29 13:41:01 -04:00
{members?.map(
(user) =>
user && (
<UserButton
key={user._id}
user={user}
2021-07-29 13:41:01 -04:00
context={channel!}
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
}
2021-08-05 09:47:00 -04:00
}, [status, channel.server]);
2021-07-29 10:11:21 -04:00
2021-08-05 09:47:00 -04:00
const users = [...client.members.keys()]
2021-07-30 18:43:26 -04:00
.map((x) => JSON.parse(x))
2021-07-30 17:40:49 -04:00
.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>
2021-08-07 15:43:08 -04:00
<ChannelDebugInfo channel={channel} />
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 }) {
if (!getState().experiments.enabled?.includes("search")) return null;
2021-07-09 09:34:36 -04:00
2021-07-21 13:27:05 -04:00
type Sort = "Relevance" | "Latest" | "Oldest";
const [sort, setSort] = useState<Sort>("Relevance");
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
2021-08-05 09:47:00 -04:00
key={key}
2021-07-21 13:27:05 -04:00
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>
<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-31 17:39:15 -04:00
href += `/server/${channel.server_id}`;
2021-07-09 09:34:36 -04:00
}
2021-07-31 17:39:15 -04:00
href += `/channel/${message.channel_id}/${message._id}`;
2021-07-09 09:34:36 -04:00
return (
2021-08-05 09:47:00 -04:00
<Link to={href} key={message._id}>
<div
style={{
margin: "2px",
padding: "6px",
background: "var(--primary-background)",
}}>
2021-07-30 17:40:49 -04:00
<b>@{message.author?.username}</b>
<br />
{message.content}
</div>
</Link>
);
})}
2021-07-09 09:34:36 -04:00
</div>
</CollapsibleSection>
);
2021-07-09 09:34:36 -04:00
}