/* * Vencord, a Discord client mod * Copyright (c) 2023 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import "./styles.css"; import { classNameFactory } from "@api/Styles"; import { openImageModal, openUserProfile } from "@utils/discord"; import { classes } from "@utils/misc"; import { ModalRoot, ModalSize, openModal } from "@utils/modal"; import { useAwaiter } from "@utils/react"; import { findByProps,findExportedComponent } from "@webpack"; import { FluxDispatcher, Forms, GuildChannelStore, GuildMemberStore, GuildStore, IconUtils, Parser, PresenceStore, RelationshipStore, ScrollerThin, SnowflakeUtils, TabBar, Timestamp, useEffect, UserStore, UserUtils, useState, useStateFromStores } from "@webpack/common"; import { Guild, User } from "discord-types/general"; const IconClasses = findByProps("icon", "acronym", "childWrapper"); const FriendRow = findExportedComponent("FriendRow"); const cl = classNameFactory("vc-gp-"); export function openGuildProfileModal(guild: Guild) { openModal(props => ); } const enum Tabs { ServerInfo, Friends, BlockedUsers } interface GuildProps { guild: Guild; } interface RelationshipProps extends GuildProps { setCount(count: number): void; } const fetched = { friends: false, blocked: false }; function renderTimestamp(timestamp: number) { return ( ); } function GuildProfileModal({ guild }: GuildProps) { const [friendCount, setFriendCount] = useState(); const [blockedCount, setBlockedCount] = useState(); useEffect(() => { fetched.friends = false; fetched.blocked = false; }, []); const [currentTab, setCurrentTab] = useState(Tabs.ServerInfo); const bannerUrl = guild.banner && IconUtils.getGuildBannerURL(guild, true)!.replace(/\?size=\d+$/, "?size=1024"); const iconUrl = guild.icon && IconUtils.getGuildIconURL({ id: guild.id, icon: guild.icon, canAnimate: true, size: 512 }); return (
{bannerUrl && currentTab === Tabs.ServerInfo && ( openImageModal(bannerUrl)} /> )}
{iconUrl ? openImageModal(iconUrl)} /> :
{guild.acronym}
}
{guild.name} {guild.description && {guild.description}}
Server Info Friends{friendCount !== undefined ? ` (${friendCount})` : ""} Blocked Users{blockedCount !== undefined ? ` (${blockedCount})` : ""}
{currentTab === Tabs.ServerInfo && } {currentTab === Tabs.Friends && } {currentTab === Tabs.BlockedUsers && }
); } function Owner(guildId: string, owner: User) { const guildAvatar = GuildMemberStore.getMember(guildId, owner.id)?.avatar; const ownerAvatarUrl = guildAvatar ? IconUtils.getGuildMemberAvatarURLSimple({ userId: owner!.id, avatar: guildAvatar, guildId, canAnimate: true }) : IconUtils.getUserAvatarURL(owner, true); return (
openImageModal(ownerAvatarUrl)} /> {Parser.parse(`<@${owner.id}>`)}
); } function ServerInfoTab({ guild }: GuildProps) { const [owner] = useAwaiter(() => UserUtils.getUser(guild.ownerId), { deps: [guild.ownerId], fallbackValue: null }); const Fields = { "Server Owner": owner ? Owner(guild.id, owner) : "Loading...", "Created At": renderTimestamp(SnowflakeUtils.extractTimestamp(guild.id)), "Joined At": guild.joinedAt ? renderTimestamp(guild.joinedAt.getTime()) : "-", // Not available in lurked guild "Vanity Link": guild.vanityURLCode ? ({`discord.gg/${guild.vanityURLCode}`}) : "-", // Making the anchor href valid would cause Discord to reload "Preferred Locale": guild.preferredLocale || "-", "Verification Level": ["None", "Low", "Medium", "High", "Highest"][guild.verificationLevel] || "?", "Nitro Boosts": `${guild.premiumSubscriberCount ?? 0} (Level ${guild.premiumTier ?? 0})`, "Channels": GuildChannelStore.getChannels(guild.id)?.count - 1 || "?", // - null category "Roles": Object.keys(GuildStore.getRoles(guild.id)).length - 1, // - @everyone }; return (
{Object.entries(Fields).map(([name, node]) =>
{name} {typeof node === "string" ? {node} : node}
)}
); } function FriendsTab({ guild, setCount }: RelationshipProps) { return UserList("friends", guild, RelationshipStore.getFriendIDs(), setCount); } function BlockedUsersTab({ guild, setCount }: RelationshipProps) { const blockedIds = Object.keys(RelationshipStore.getRelationships()).filter(id => RelationshipStore.isBlocked(id)); return UserList("blocked", guild, blockedIds, setCount); } function UserList(type: "friends" | "blocked", guild: Guild, ids: string[], setCount: (count: number) => void) { const missing = [] as string[]; const members = [] as string[]; for (const id of ids) { if (GuildMemberStore.isMember(guild.id, id)) members.push(id); else missing.push(id); } // Used for side effects (rerender on member request success) useStateFromStores( [GuildMemberStore], () => GuildMemberStore.getMemberIds(guild.id), null, (old, curr) => old.length === curr.length ); useEffect(() => { if (!fetched[type] && missing.length) { fetched[type] = true; FluxDispatcher.dispatch({ type: "GUILD_MEMBERS_REQUEST", guildIds: [guild.id], userIds: missing }); } }, []); useEffect(() => setCount(members.length), [members.length]); return ( {members.map(id => openUserProfile(id)} onContextMenu={() => { }} /> )} ); }