diff --git a/package.json b/package.json
index aa6a30309ef9b8f56e219611e07a6705e22d25ee..c2d8fb9d09fd43dfbd5a70a93174d30d7e2b1fe1 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,7 @@
     "react-router-dom": "^5.2.0",
     "react-scroll": "^1.8.2",
     "redux": "^4.1.0",
-    "revolt.js": "4.3.3-alpha.16",
+    "revolt.js": "4.3.3-alpha.17",
     "rimraf": "^3.0.2",
     "sass": "^1.35.1",
     "shade-blend-color": "^1.0.0",
diff --git a/src/pages/settings/server/Bans.tsx b/src/pages/settings/server/Bans.tsx
index 6497bba665992d8ebbe3d07e728b0489366e88c2..b196a2085944aea3091bc9a384accf5708fca43b 100644
--- a/src/pages/settings/server/Bans.tsx
+++ b/src/pages/settings/server/Bans.tsx
@@ -1,5 +1,6 @@
 import { XCircle } from "@styled-icons/boxicons-regular";
 import { Servers, Users } from "revolt.js/dist/api/objects";
+import { Route } from "revolt.js/dist/api/routes";
 
 import styles from "./Panes.module.scss";
 import { Text } from "preact-i18n";
@@ -19,11 +20,7 @@ export function Bans({ server }: Props) {
     const client = useContext(AppContext);
     const [deleting, setDelete] = useState<string[]>([]);
     const [data, setData] = useState<
-        | {
-              users: Pick<Users.User, "_id" | "username" | "avatar">[];
-              bans: Servers.Ban[];
-          }
-        | undefined
+        Route<"GET", "/servers/id/bans">["response"] | undefined
     >(undefined);
 
     useEffect(() => {
diff --git a/src/pages/settings/server/Invites.tsx b/src/pages/settings/server/Invites.tsx
index 594c1c5813b1ff0a4d693bc88fe331c48ed7712c..ce4117059ef49148e38272fc9393edae647ae134 100644
--- a/src/pages/settings/server/Invites.tsx
+++ b/src/pages/settings/server/Invites.tsx
@@ -64,12 +64,14 @@ export function Invites({ server }: Props) {
                         <code>{invite._id}</code>
                         <span>
                             <UserIcon target={creator} size={24} />{" "}
-                            {creator?.username ?? "unknown"}
+                            {creator?.username ?? (
+                                <Text id="app.main.channel.unknown_user" />
+                            )}
                         </span>
                         <span>
                             {channel && creator
                                 ? getChannelName(ctx.client, channel, true)
-                                : "#unknown"}
+                                : "#??"}
                         </span>
                         <IconButton
                             onClick={async () => {
diff --git a/src/pages/settings/server/Members.tsx b/src/pages/settings/server/Members.tsx
index 9bfeb9dad171286adc874e36bd72f43974d52918..4f83a683652298eeef5fff6033169b463a1e3308 100644
--- a/src/pages/settings/server/Members.tsx
+++ b/src/pages/settings/server/Members.tsx
@@ -1,21 +1,30 @@
+import { ChevronDown } from "@styled-icons/boxicons-regular";
+import { isEqual } from "lodash";
 import { Servers } from "revolt.js/dist/api/objects";
 
 import styles from "./Panes.module.scss";
+import { Text } from "preact-i18n";
 import { useEffect, useState } from "preact/hooks";
 
 import { useForceUpdate, useUsers } from "../../../context/revoltjs/hooks";
 
+import UserIcon from "../../../components/common/user/UserIcon";
+import Button from "../../../components/ui/Button";
+import Checkbox from "../../../components/ui/Checkbox";
+import IconButton from "../../../components/ui/IconButton";
+import Overline from "../../../components/ui/Overline";
+
 interface Props {
     server: Servers.Server;
 }
 
-// ! FIXME: bad code :)
 export function Members({ server }: Props) {
     const [members, setMembers] = useState<Servers.Member[] | undefined>(
         undefined,
     );
 
     const ctx = useForceUpdate();
+    const [selected, setSelected] = useState<undefined | string>();
     const users = useUsers(members?.map((x) => x._id.user) ?? [], ctx);
 
     useEffect(() => {
@@ -24,21 +33,125 @@ export function Members({ server }: Props) {
             .then((members) => setMembers(members));
     }, []);
 
+    const [roles, setRoles] = useState<string[]>([]);
+    useEffect(() => {
+        if (selected) {
+            setRoles(
+                members!.find((x) => x._id.user === selected)?.roles ?? [],
+            );
+        }
+    }, [selected]);
+
     return (
-        <div className={styles.members}>
+        <div className={styles.userList}>
             <div className={styles.subtitle}>
                 {members?.length ?? 0} Members
             </div>
             {members &&
                 members.length > 0 &&
-                users?.map(
-                    (x) =>
-                        x && (
-                            <div className={styles.member}>
-                                <div>@{x.username}</div>
+                members
+                    .map((x) => {
+                        return {
+                            member: x,
+                            user: users.find((y) => y?._id === x._id.user),
+                        };
+                    })
+                    .map(({ member, user }) => (
+                        <>
+                            <div
+                                key={member._id.user}
+                                className={styles.member}
+                                data-open={selected === member._id.user}
+                                onClick={() =>
+                                    setSelected(
+                                        selected === member._id.user
+                                            ? undefined
+                                            : member._id.user,
+                                    )
+                                }>
+                                <span>
+                                    <UserIcon target={user} size={24} />{" "}
+                                    {user?.username ?? (
+                                        <Text id="app.main.channel.unknown_user" />
+                                    )}
+                                </span>
+                                <IconButton className={styles.chevron}>
+                                    <ChevronDown size={24} />
+                                </IconButton>
                             </div>
-                        ),
-                )}
+                            {selected === member._id.user && (
+                                <div
+                                    key={"drop_" + member._id.user}
+                                    className={styles.memberView}>
+                                    <Overline type="subtle">Roles</Overline>
+                                    {Object.keys(server.roles ?? {}).map(
+                                        (key) => {
+                                            let role = server.roles![key];
+                                            return (
+                                                <Checkbox
+                                                    checked={
+                                                        roles.includes(key) ??
+                                                        false
+                                                    }
+                                                    onChange={(v) => {
+                                                        if (v) {
+                                                            setRoles([
+                                                                ...roles,
+                                                                key,
+                                                            ]);
+                                                        } else {
+                                                            setRoles(
+                                                                roles.filter(
+                                                                    (x) =>
+                                                                        x !==
+                                                                        key,
+                                                                ),
+                                                            );
+                                                        }
+                                                    }}>
+                                                    <span
+                                                        style={{
+                                                            color: role.colour,
+                                                        }}>
+                                                        {role.name}
+                                                    </span>
+                                                </Checkbox>
+                                            );
+                                        },
+                                    )}
+                                    <Button
+                                        compact
+                                        disabled={isEqual(
+                                            member.roles ?? [],
+                                            roles,
+                                        )}
+                                        onClick={async () => {
+                                            await ctx.client.servers.members.editMember(
+                                                server._id,
+                                                member._id.user,
+                                                {
+                                                    roles,
+                                                },
+                                            );
+
+                                            setMembers(
+                                                members.map((x) =>
+                                                    x._id.user ===
+                                                    member._id.user
+                                                        ? {
+                                                              ...x,
+                                                              roles,
+                                                          }
+                                                        : x,
+                                                ),
+                                            );
+                                        }}>
+                                        <Text id="app.special.modals.actions.save" />
+                                    </Button>
+                                </div>
+                            )}
+                        </>
+                    ))}
         </div>
     );
 }
diff --git a/src/pages/settings/server/Panes.module.scss b/src/pages/settings/server/Panes.module.scss
index 6837a8389097b58d4f72d4018614078092283cc6..117f8fa2d7591526010a8231a5df1c058d9d3749 100644
--- a/src/pages/settings/server/Panes.module.scss
+++ b/src/pages/settings/server/Panes.module.scss
@@ -41,7 +41,8 @@
     }
 
     .invite,
-    .ban {
+    .ban,
+    .member {
         gap: 8px;
         padding: 10px;
         display: flex;
@@ -69,25 +70,23 @@
             opacity: 0.5;
         }
     }
-}
 
-.members {
-    .subtitle {
-        display: flex;
-        justify-content: space-between;
-        font-size: 13px;
-        text-transform: uppercase;
-        color: var(--secondary-foreground);
-        font-weight: 700;
+    .member {
+        cursor: pointer;
+
+        .chevron {
+            transition: 0.2s ease all;
+        }
+
+        &:not([data-open="true"]) .chevron {
+            transform: rotateZ(90deg);
+        }
     }
 
-    .member {
-        gap: 8px;
+    .memberView {
         padding: 10px;
-        display: flex;
-        align-items: center;
-        flex-direction: row;
-        background: var(--secondary-background);
+        margin: 0 10px;
+        background: var(--background);
     }
 }
 
diff --git a/yarn.lock b/yarn.lock
index 5e18fae5e65d0d566d2f7d58594dd5568dfbb163..db7d5ac6214abc9601a7960530e61194ea03c853 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3563,10 +3563,10 @@ reusify@^1.0.4:
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-revolt.js@4.3.3-alpha.16:
-  version "4.3.3-alpha.16"
-  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.16.tgz#ed595d34cdefc1d8756694787abda01e28d373e8"
-  integrity sha512-UejqRKYoO98Uj2eki6dZMbEbX8msYz/JgY3EYxhbe1qMnBvLD8JxjcemHTLBf2Iytom8fFQ1EV0ee4Z89Jkcjw==
+revolt.js@4.3.3-alpha.17:
+  version "4.3.3-alpha.17"
+  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.17.tgz#0745d251c695840b87e98098bcc4d67c7cc15de5"
+  integrity sha512-MjxVnkkeX5md5NxZNRS9fl06jsjcDciAxKnbZ2rkBYJofQ94tvr1CYBWvFhS/u/tAR80HAPIEjJVC9HKJDK9Fg==
   dependencies:
     "@insertish/mutable" "1.1.0"
     axios "^0.19.2"