diff --git a/external/lang b/external/lang
index 0dc9e46b376621b8af99784a7134fb8648cc3701..588b882a3acca644c2f65b67cd341c88fd97989d 160000
--- a/external/lang
+++ b/external/lang
@@ -1 +1 @@
-Subproject commit 0dc9e46b376621b8af99784a7134fb8648cc3701
+Subproject commit 588b882a3acca644c2f65b67cd341c88fd97989d
diff --git a/package.json b/package.json
index d22d515093e93ce68c0db8bee05613a019348b11..a89609945ac03a43f1585f36420d845daee1d37d 100644
--- a/package.json
+++ b/package.json
@@ -78,7 +78,7 @@
     "react-router-dom": "^5.2.0",
     "react-scroll": "^1.8.2",
     "redux": "^4.1.0",
-    "revolt.js": "4.3.3-alpha.4",
+    "revolt.js": "4.3.3-alpha.6",
     "rimraf": "^3.0.2",
     "sass": "^1.35.1",
     "shade-blend-color": "^1.0.0",
diff --git a/src/components/ui/Tip.tsx b/src/components/ui/Tip.tsx
index 910bb7f13446e125fecd13cf19b82a349f56b1dc..489572b915f688b63a9101c50e8630b12a8d4ed6 100644
--- a/src/components/ui/Tip.tsx
+++ b/src/components/ui/Tip.tsx
@@ -1,8 +1,13 @@
-import styled from "styled-components";
-import { InfoCircle } from "@styled-icons/boxicons-regular";
 import { Children } from "../../types/Preact";
+import styled, { css } from "styled-components";
+import { InfoCircle } from "@styled-icons/boxicons-regular";
+
+interface Props {
+    warning?: boolean
+    error?: boolean
+}
 
-export const TipBase = styled.div`
+export const TipBase = styled.div<Props>`
     display: flex;
     padding: 12px;
     overflow: hidden;
@@ -24,11 +29,24 @@ export const TipBase = styled.div`
         flex-shrink: 0;
         margin-inline-end: 10px;
     }
+
+    ${ props => props.warning && css`
+        color: var(--warning);
+        border: 2px solid var(--warning);
+        background: var(--secondary-header);
+    ` }
+
+    ${ props => props.error && css`
+        color: var(--error);
+        border: 2px solid var(--error);
+        background: var(--secondary-header);
+    ` }
 `;
 
-export default function Tip(props: { children: Children }) {
+export default function Tip(props: Props & { children: Children }) {
+    const { children, ...tipProps } = props;
     return (
-        <TipBase>
+        <TipBase {...tipProps}>
             <InfoCircle size={20} />
             <span>{props.children}</span>
         </TipBase>
diff --git a/src/pages/settings/ChannelSettings.tsx b/src/pages/settings/ChannelSettings.tsx
index 4039779e4e646ba7c54c9c1ef36f4007f406697a..aed5ca6950b2c6164bb5c516382e3609611064e7 100644
--- a/src/pages/settings/ChannelSettings.tsx
+++ b/src/pages/settings/ChannelSettings.tsx
@@ -1,12 +1,13 @@
 import { Text } from "preact-i18n";
-import { ListUl } from "@styled-icons/boxicons-regular";
 import Category from "../../components/ui/Category";
 import { GenericSettings } from "./GenericSettings";
 import { getChannelName } from "../../context/revoltjs/util";
 import { Route, useHistory, useParams } from "react-router-dom";
+import { ListCheck, ListUl } from "@styled-icons/boxicons-regular";
 import { useChannel, useForceUpdate } from "../../context/revoltjs/hooks";
 
-import { Overview } from "./channel/Overview";
+import Overview from "./channel/Overview";
+import Permissions from "./channel/Permissions";
 
 export default function ChannelSettings() {
     const { channel: cid } = useParams<{ channel: string; }>();
@@ -17,10 +18,17 @@ export default function ChannelSettings() {
 
     const history = useHistory();
     function switchPage(to?: string) {
+        let base_url;
+        switch (channel?.channel_type) {
+            case 'TextChannel':
+            case 'VoiceChannel': base_url = `/server/${channel.server}/channel/${cid}/settings`; break;
+            default: base_url = `/channel/${cid}/settings`;
+        }
+
         if (to) {
-            history.replace(`/channel/${cid}/settings/${to}`);
+            history.replace(`${base_url}/${to}`);
         } else {
-            history.replace(`/channel/${cid}/settings`);
+            history.replace(base_url);
         }
     }
 
@@ -32,9 +40,17 @@ export default function ChannelSettings() {
                     id: 'overview',
                     icon: <ListUl size={20} />,
                     title: <Text id="app.settings.channel_pages.overview.title" />
+                },
+                {
+                    id: 'permissions',
+                    icon: <ListCheck size={20} />,
+                    title: <Text id="app.settings.channel_pages.permissions.title" />
                 }
             ]}
             children={[
+                <Route path="/server/:server/channel/:channel/settings/permissions"><Permissions channel={channel} /></Route>,
+                <Route path="/channel/:channel/settings/permissions"><Permissions channel={channel} /></Route>,
+
                 <Route path="/"><Overview channel={channel} /></Route>
             ]}
             category="channel_pages"
diff --git a/src/pages/settings/channel/Overview.tsx b/src/pages/settings/channel/Overview.tsx
index 60e8cce2784f296b2adb934e38b6d5324869035b..f41f123bd45242c04cf6556e68a4b03900d62a70 100644
--- a/src/pages/settings/channel/Overview.tsx
+++ b/src/pages/settings/channel/Overview.tsx
@@ -12,7 +12,7 @@ interface Props {
     channel: Channels.GroupChannel | Channels.TextChannel | Channels.VoiceChannel;
 }
 
-export function Overview({ channel }: Props) {
+export default function Overview({ channel }: Props) {
     const client = useContext(AppContext);
 
     const [name, setName] = useState(channel.name);
@@ -81,9 +81,11 @@ export function Overview({ channel }: Props) {
                     if (!changed) setChanged(true)
                 }}
             />
-            <Button onClick={save} contrast disabled={!changed}>
-                <Text id="app.special.modals.actions.save" />
-            </Button>
+            <p>
+                <Button onClick={save} contrast disabled={!changed}>
+                    <Text id="app.special.modals.actions.save" />
+                </Button>
+            </p>
         </div>
     );
 }
diff --git a/src/pages/settings/channel/Permissions.tsx b/src/pages/settings/channel/Permissions.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..7fc8c2e694790082a7c4cc103d3fc8e02dc9ba38
--- /dev/null
+++ b/src/pages/settings/channel/Permissions.tsx
@@ -0,0 +1,91 @@
+import Tip from "../../../components/ui/Tip";
+import Button from "../../../components/ui/Button";
+import { Channels } from "revolt.js/dist/api/objects";
+import Checkbox from "../../../components/ui/Checkbox";
+import { useServer } from "../../../context/revoltjs/hooks";
+import { useContext, useEffect, useState } from "preact/hooks";
+import { ChannelPermission } from "revolt.js/dist/api/permissions";
+import { AppContext } from "../../../context/revoltjs/RevoltClient";
+
+// ! FIXME: export from revolt.js
+const DEFAULT_PERMISSION_DM = ChannelPermission.View
+    + ChannelPermission.SendMessage
+    + ChannelPermission.ManageChannel
+    + ChannelPermission.VoiceCall
+    + ChannelPermission.InviteOthers
+    + ChannelPermission.EmbedLinks
+    + ChannelPermission.UploadFiles;
+
+interface Props {
+    channel: Channels.GroupChannel | Channels.TextChannel | Channels.VoiceChannel;
+}
+
+// ! FIXME: bad code :)
+export default function Permissions({ channel }: Props) {
+    const [ selected, setSelected ] = useState('default');
+    const client = useContext(AppContext);
+
+    type R = { name: string, permissions: number };
+    let roles: { [key: string]: R } = {};
+    if (channel.channel_type !== 'Group') {
+        const server = useServer(channel.server);
+        const a = server?.roles ?? {};
+        for (let b of Object.keys(a)) {
+            roles[b] = {
+                name: a[b].name,
+                permissions: a[b].permissions[1]
+            };
+        }
+    }
+
+    const keys = [ 'default', ...Object.keys(roles) ];
+
+    const defaultRole = { name: 'Default', permissions: (channel.channel_type === 'Group' ? channel.permissions : channel.default_permissions) ?? DEFAULT_PERMISSION_DM };
+    const selectedRole = selected === 'default' ? defaultRole : roles[selected];
+
+    if (!selectedRole) {
+        useEffect(() => setSelected('default'), [ ]);
+        return null;
+    }
+
+    const [ p, setPerm ] = useState(selectedRole.permissions >>> 0);
+
+    useEffect(() => {
+        setPerm(selectedRole.permissions >>> 0);
+    }, [ selected, selectedRole.permissions ]);
+    
+    return (
+        <div>
+            <Tip warning>This section is under construction.</Tip>
+            <h2>select role</h2>
+            { selected }
+            { keys
+                .map(id => {
+                    let role: R = id === 'default' ? defaultRole : roles[id];
+
+                    return (
+                        <Checkbox checked={selected === id} onChange={selected => selected && setSelected(id)}>
+                            { role.name }
+                        </Checkbox>
+                    )
+                })
+            }
+            <h2>channel per??issions</h2>
+            { Object.keys(ChannelPermission)
+                .map(perm => {
+                    let value = ChannelPermission[perm as keyof typeof ChannelPermission];
+                    if (value & DEFAULT_PERMISSION_DM) {
+                        return (
+                            <Checkbox checked={(p & value) > 0} onChange={c => setPerm(c ? (p | value) : (p ^ value))}>
+                                { perm }
+                            </Checkbox>
+                        )
+                    }
+                })
+            }
+            <Button contrast onClick={() => {
+                client.channels.setPermissions(channel._id, selected, p);
+            }}>click here to save permissions for role</Button>
+        </div>
+    );
+}
diff --git a/src/pages/settings/panes/Feedback.tsx b/src/pages/settings/panes/Feedback.tsx
index 8aeeafe21eed33ce0492dbfca24809abebc0377c..66d21cd692056cb77dde2a911bb783de22b7159d 100644
--- a/src/pages/settings/panes/Feedback.tsx
+++ b/src/pages/settings/panes/Feedback.tsx
@@ -69,7 +69,7 @@ export function Feedback() {
                 </Radio> }
                 <Radio
                     disabled={state === "sending"}
-                    checked={checked === "__other_option__"}
+                    checked={checked === "__other_option__" && other !== "Revite"}
                     onSelect={() => setChecked("__other_option__")}>
                     <Localizer>
                         <InputBox
@@ -96,9 +96,11 @@ export function Feedback() {
                 disabled={state === "sending"}
                 onChange={ev => setDescription(ev.currentTarget.value)}
             />
-            <Button type="submit" contrast>
-                <Text id="app.settings.pages.feedback.send" />
-            </Button>
+            <p>
+                <Button type="submit" contrast>
+                    <Text id="app.settings.pages.feedback.send" />
+                </Button>
+            </p>
         </form>
     );
 }
diff --git a/src/pages/settings/panes/Profile.tsx b/src/pages/settings/panes/Profile.tsx
index 148f1b4782292f6576d1b4cb1b1aa6bb03b41e3e..39902c0c37451d4cab2885131006cb7c2dc83822 100644
--- a/src/pages/settings/panes/Profile.tsx
+++ b/src/pages/settings/panes/Profile.tsx
@@ -113,14 +113,16 @@ export function Profile() {
                     intl.dictionary
                 )}
             />
-            <Button contrast
-                onClick={() => {
-                    setChanged(false);
-                    ctx.client.users.editUser({ profile: { content: profile?.content } })
-                }}
-                disabled={!changed}>
-                <Text id="app.special.modals.actions.save" />
-            </Button>
+            <p>
+                <Button contrast
+                    onClick={() => {
+                        setChanged(false);
+                        ctx.client.users.editUser({ profile: { content: profile?.content } })
+                    }}
+                    disabled={!changed}>
+                    <Text id="app.special.modals.actions.save" />
+                </Button>
+            </p>
         </div>
     );
 }
diff --git a/src/pages/settings/server/Bans.tsx b/src/pages/settings/server/Bans.tsx
index 7d8a1590fc7ddceee953ef528a730b37dffd9a19..5ec7c0f0581a3e0eb0e9ba7b2a46053474b0f1d0 100644
--- a/src/pages/settings/server/Bans.tsx
+++ b/src/pages/settings/server/Bans.tsx
@@ -1,3 +1,4 @@
+import Tip from "../../../components/ui/Tip";
 import { Servers } from "revolt.js/dist/api/objects";
 import { useContext, useEffect, useState } from "preact/hooks";
 import { AppContext } from "../../../context/revoltjs/RevoltClient";
@@ -17,6 +18,7 @@ export function Bans({ server }: Props) {
 
     return (
         <div>
+            <Tip warning>This section is under construction.</Tip>
             { bans?.map(x => <div>{x._id.user}: {x.reason ?? 'no reason'} <button onClick={() => client.servers.unbanUser(server._id, x._id.user)}>unban</button></div>) }
         </div>
     );
diff --git a/src/pages/settings/server/Members.tsx b/src/pages/settings/server/Members.tsx
index d4fb3c83291bc7a69c1e442d05f7b590f02bbec9..b569e71afcda26451413104da704755282d396aa 100644
--- a/src/pages/settings/server/Members.tsx
+++ b/src/pages/settings/server/Members.tsx
@@ -1,13 +1,17 @@
 import { useEffect, useState } from "preact/hooks";
 import { Servers } from "revolt.js/dist/api/objects";
+import Checkbox from "../../../components/ui/Checkbox";
+import Tip from "../../../components/ui/Tip";
 import { useForceUpdate, useUsers } from "../../../context/revoltjs/hooks";
 
 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 users = useUsers(members?.map(x => x._id.user) ?? [], ctx);
 
@@ -18,7 +22,36 @@ export function Members({ server }: Props) {
 
     return (
         <div>
-            { members && members.length > 0 && users?.map(x => x && <div>@{x.username}</div>) }
+            <Tip warning>This section is under construction.</Tip>
+            { members && members.length > 0 && users?.map(x => x && <div>
+                <br/>
+                <br/>
+                <br/>
+
+                <span>@{x.username}</span>
+                { server.roles && Object.keys(server.roles).map(id => {
+                    let role = server.roles?.[id]!;
+                    let member = members.find(y => x._id === y._id.user)!;
+
+                    return (
+                        <Checkbox checked={member.roles?.includes(id) ?? false} onChange={selected => {
+                            let roles = (member.roles ?? []).filter(z => z !== id);
+                            if (selected) roles.push(id);
+
+                            ctx.client.servers.members.editMember(server._id, x._id, { roles });
+                            setMembers(
+                                [
+                                    ...members.filter(e => e._id.user !== x._id),
+                                    {
+                                        ...member,
+                                        roles
+                                    }
+                                ]
+                            );
+                        }}>{ role.name }</Checkbox>
+                    )
+                }) }
+            </div>) }
         </div>
     );
 }
diff --git a/src/pages/settings/server/Overview.tsx b/src/pages/settings/server/Overview.tsx
index d6d0c2842233f583ecb5458448149045a23dcb18..fe530276a1736e84f6077ba407b18bacb1254a07 100644
--- a/src/pages/settings/server/Overview.tsx
+++ b/src/pages/settings/server/Overview.tsx
@@ -76,9 +76,11 @@ export function Overview({ server }: Props) {
                     if (!changed) setChanged(true)
                 }}
             />
-            <Button onClick={save} contrast disabled={!changed}>
-                <Text id="app.special.modals.actions.save" />
-            </Button>
+            <p>
+                <Button onClick={save} contrast disabled={!changed}>
+                    <Text id="app.special.modals.actions.save" />
+                </Button>
+            </p>
 
             <h3>
                 <Text id="app.main.servers.custom_banner" />
diff --git a/src/pages/settings/server/Roles.tsx b/src/pages/settings/server/Roles.tsx
index 47e82023050739831b2891e98012a8b24d29e33d..5d530c1dca3b37544842a67397dbee0f7c1631ba 100644
--- a/src/pages/settings/server/Roles.tsx
+++ b/src/pages/settings/server/Roles.tsx
@@ -1,15 +1,20 @@
-import { useEffect, useState } from "preact/hooks";
+import Tip from "../../../components/ui/Tip";
 import Button from "../../../components/ui/Button";
 import { Servers } from "revolt.js/dist/api/objects";
+import InputBox from "../../../components/ui/InputBox";
 import Checkbox from "../../../components/ui/Checkbox";
+import { useContext, useEffect, useState } from "preact/hooks";
+import { AppContext } from "../../../context/revoltjs/RevoltClient";
 import { ChannelPermission, ServerPermission } from "revolt.js/dist/api/permissions";
 
 interface Props {
     server: Servers.Server;
 }
 
+// ! FIXME: bad code :)
 export function Roles({ server }: Props) {
     const [ selected, setSelected ] = useState('default');
+    const client = useContext(AppContext);
 
     const roles = server.roles ?? {};
     const keys = [ 'default', ...Object.keys(roles) ];
@@ -21,10 +26,26 @@ export function Roles({ server }: Props) {
         useEffect(() => setSelected('default'), [ ]);
         return null;
     }
+
+    const [ p, setPerm ] = useState([
+        selectedRole.permissions[0] >>> 0,
+        selectedRole.permissions[1] >>> 0,
+    ]);
+
+    useEffect(() => {
+        setPerm([
+            selectedRole.permissions[0] >>> 0,
+            selectedRole.permissions[1] >>> 0,
+        ]);
+    }, [ selected, selectedRole.permissions ]);
+
+    const [ name, setName ] = useState('');
     
     return (
         <div>
+            <Tip warning>This section is under construction.</Tip>
             <h2>select role</h2>
+            { selected }
             { keys
                 .map(id => {
                     let role: Servers.Role = id === 'default' ? defaultRole : roles[id];
@@ -36,14 +57,21 @@ export function Roles({ server }: Props) {
                     )
                 })
             }
-            <Button disabled={selected === 'default'} error onClick={() => {}}>delete role</Button>
-            <h2>server permmissions</h2>
+            <Button disabled={selected === 'default'} error onClick={() => {
+                setSelected('default');
+                client.servers.deleteRole(server._id, selected);
+            }}>delete role</Button><br/>
+            <InputBox placeholder="role name" value={name} onChange={e => setName(e.currentTarget.value)} />
+            <Button contrast onClick={() => {
+                client.servers.createRole(server._id, name);
+            }}>create</Button>
+            <h2>serverm permmissions</h2>
             { Object.keys(ServerPermission)
                 .map(perm => {
                     let value = ServerPermission[perm as keyof typeof ServerPermission];
 
                     return (
-                        <Checkbox checked={((selectedRole.permissions[0] >>> 0) & value) > 0} onChange={() => {}}>
+                        <Checkbox checked={(p[0] & value) > 0} onChange={c => setPerm([ c ? (p[0] | value) : (p[0] ^ value), p[1] ])}>
                             { perm }
                         </Checkbox>
                     )
@@ -55,12 +83,15 @@ export function Roles({ server }: Props) {
                     let value = ChannelPermission[perm as keyof typeof ChannelPermission];
 
                     return (
-                        <Checkbox checked={((selectedRole.permissions[1] >>> 0) & value) > 0} onChange={() => {}}>
+                        <Checkbox checked={((p[1] >>> 0) & value) > 0} onChange={c => setPerm([ p[0], c ? (p[1] | value) : (p[1] ^ value) ])}>
                             { perm }
                         </Checkbox>
                     )
                 })
             }
+            <Button contrast onClick={() => {
+                client.servers.setPermissions(server._id, selected, { server: p[0], channel: p[1] });
+            }}>click here to save permissions for role</Button>
         </div>
     );
 }
diff --git a/yarn.lock b/yarn.lock
index b3a3e352c05cdda0b09e34b029fa6c15f07d9777..1a95434bc21aa725e1bf33fe3b815d17b8b8622e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3420,10 +3420,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.4:
-  version "4.3.3-alpha.4"
-  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.4.tgz#7d393c9016a9d89151b1c091f6b02bc193b3a553"
-  integrity sha512-d6SGjRKFDlWG5fEveaVf0DRGb8d0RW8iv1E0kEG0W3R138KdeWCK8zUU0H+ykUdd5OjS7ESBKaEcwSP2BXMRSA==
+revolt.js@4.3.3-alpha.6:
+  version "4.3.3-alpha.6"
+  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.6.tgz#054e685a5c0dac2c7ae3e2aa454d1965218cb2b0"
+  integrity sha512-u1/xf+YSQr8DbKsO0raym+F05R75bqYadrPWaIie3m2s2p7ZWeamHlfWIKJlmDO5AL+Lg3xoZWoLwuRHrD1K/Q==
   dependencies:
     "@insertish/mutable" "1.1.0"
     axios "^0.19.2"