feat: switch to revolt.js@6.0.0 + new revolt-api

This commit is contained in:
Paul Makles
2022-04-09 15:47:04 +01:00
parent e9585a66a8
commit 48ff1dcf92
91 changed files with 528 additions and 460 deletions

View File

@@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import styled from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -1,5 +1,4 @@
import { Channel } from "revolt.js/dist/maps/Channels";
import { User } from "revolt.js/dist/maps/Users";
import { Channel, User } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { StateUpdater, useState } from "preact/hooks";

View File

@@ -1,14 +1,15 @@
import { Hash, VolumeFull } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import { useContext } from "preact/hooks";
import { AppContext } from "../../context/revoltjs/RevoltClient";
import { ImageIconBase, IconBaseProps } from "./IconBase";
import fallback from "./assets/group.png";
import { ImageIconBase, IconBaseProps } from "./IconBase";
interface Props extends IconBaseProps<Channel> {
isServerChannel?: boolean;
}
@@ -32,7 +33,7 @@ export default observer(
...imgProps
} = props;
const iconURL = client.generateFileURL(
target?.icon ?? attachment,
target?.icon ?? attachment ?? undefined,
{ max_side: 256 },
animate,
);

View File

@@ -1,10 +1,11 @@
import { Attachment } from "revolt-api/types/Autumn";
import { API } from "revolt.js";
import { Nullable } from "revolt.js/dist/util/null";
import styled, { css } from "styled-components/macro";
export interface IconBaseProps<T> {
target?: T;
url?: string;
attachment?: Attachment;
attachment?: Nullable<API.File>;
size: number;
hover?: boolean;

View File

@@ -2,8 +2,7 @@ import { Check } from "@styled-icons/boxicons-regular";
import { Cog } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link } from "react-router-dom";
import { Permission } from "revolt.js/dist/api/permissions";
import { Server } from "revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { Server } from "revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import styled from "styled-components/macro";
import { useContext } from "preact/hooks";
@@ -39,7 +39,7 @@ export default observer(
const { target, attachment, size, animate, server_name, ...imgProps } =
props;
const iconURL = client.generateFileURL(
target?.icon ?? attachment,
target?.icon ?? attachment ?? undefined,
{ max_side: 256 },
animate,
);

View File

@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { Message as MessageObject } from "revolt.js/dist/maps/Messages";
import { Message as MessageObject } from "revolt.js";
import { attachContextMenu } from "preact-context-menu";
import { memo } from "preact/compat";

View File

@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { Message } from "revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import styled, { css, keyframes } from "styled-components/macro";
import { decodeTime } from "ulid";

View File

@@ -1,8 +1,7 @@
import { Send, ShieldX, HappyBeaming, Box } from "@styled-icons/boxicons-solid";
import { Send, ShieldX } from "@styled-icons/boxicons-solid";
import Axios, { CancelTokenSource } from "axios";
import { observer } from "mobx-react-lite";
import { Permission } from "revolt.js/dist/api/permissions";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel, Permission } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { ulid } from "ulid";

View File

@@ -11,8 +11,7 @@ import {
MessageSquareEdit,
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { SystemMessage as SystemMessageI } from "revolt-api/types/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Message, API } from "revolt.js";
import styled from "styled-components/macro";
import { attachContextMenu } from "preact-context-menu";
@@ -75,7 +74,8 @@ export const SystemMessage = observer(
({ attachContext, message, highlight, hideInfo }: Props) => {
const data = message.asSystemMessage;
const SystemMessageIcon =
iconDictionary[data.type as SystemMessageI["type"]] ?? InfoCircle;
iconDictionary[data.type as API.SystemMessage["type"]] ??
InfoCircle;
let children;
switch (data.type) {

View File

@@ -1,4 +1,4 @@
import { Attachment as AttachmentI } from "revolt-api/types/Autumn";
import { API } from "revolt.js";
import styles from "./Attachment.module.scss";
import classNames from "classnames";
@@ -14,7 +14,7 @@ import Spoiler from "./Spoiler";
import TextFile from "./TextFile";
interface Props {
attachment: AttachmentI;
attachment: API.File;
hasContent?: boolean;
}

View File

@@ -4,7 +4,7 @@ import {
Download,
} from "@styled-icons/boxicons-regular";
import { File, Video } from "@styled-icons/boxicons-solid";
import { Attachment } from "revolt-api/types/Autumn";
import { API } from "revolt.js";
import styles from "./AttachmentActions.module.scss";
import classNames from "classnames";
@@ -17,7 +17,7 @@ import { AppContext } from "../../../../context/revoltjs/RevoltClient";
import IconButton from "../../../ui/IconButton";
interface Props {
attachment: Attachment;
attachment: API.File;
}
export default function AttachmentActions({ attachment }: Props) {

View File

@@ -1,4 +1,4 @@
import { Attachment } from "revolt-api/types/Autumn";
import { API } from "revolt.js";
import styles from "./Attachment.module.scss";
import classNames from "classnames";
@@ -10,12 +10,12 @@ import { AppContext } from "../../../../context/revoltjs/RevoltClient";
enum ImageLoadingState {
Loading,
Loaded,
Error
Error,
}
type Props = JSX.HTMLAttributes<HTMLImageElement> & {
attachment: Attachment;
}
attachment: API.File;
};
export default function ImageFile({ attachment, ...props }: Props) {
const [loading, setLoading] = useState(ImageLoadingState.Loading);
@@ -23,25 +23,19 @@ export default function ImageFile({ attachment, ...props }: Props) {
const { openScreen } = useIntermediate();
const url = client.generateFileURL(attachment)!;
return <img
{...props}
src={url}
alt={attachment.filename}
loading="lazy"
className={classNames(styles.image, {
[styles.loading]: loading !== ImageLoadingState.Loaded
})}
onClick={() =>
openScreen({ id: "image_viewer", attachment })
}
onMouseDown={(ev) =>
ev.button === 1 && window.open(url, "_blank")
}
onLoad={() =>
setLoading(ImageLoadingState.Loaded)
}
onError={() =>
setLoading(ImageLoadingState.Error)
}
/>
return (
<img
{...props}
src={url}
alt={attachment.filename}
loading="lazy"
className={classNames(styles.image, {
[styles.loading]: loading !== ImageLoadingState.Loaded,
})}
onClick={() => openScreen({ id: "image_viewer", attachment })}
onMouseDown={(ev) => ev.button === 1 && window.open(url, "_blank")}
onLoad={() => setLoading(ImageLoadingState.Loaded)}
onError={() => setLoading(ImageLoadingState.Error)}
/>
);
}

View File

@@ -2,9 +2,7 @@ import { Reply } from "@styled-icons/boxicons-regular";
import { File } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { RelationshipStatus } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Channel, Message, API } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { Text } from "preact-i18n";
@@ -174,7 +172,7 @@ export const MessageReply = observer(
<ReplyBase head={index === 0}>
{/*<Reply size={16} />*/}
{message.author?.relationship === RelationshipStatus.Blocked ? (
{message.author?.relationship === "Blocked" ? (
<Text id="app.main.channel.misc.blocked_user" />
) : (
<>

View File

@@ -1,5 +1,5 @@
import axios from "axios";
import { Attachment } from "revolt-api/types/Autumn";
import { API } from "revolt.js";
import styles from "./Attachment.module.scss";
import { useContext, useEffect, useState } from "preact/hooks";
@@ -13,7 +13,7 @@ import {
import Preloader from "../../../ui/Preloader";
interface Props {
attachment: Attachment;
attachment: API.File;
}
const fileCache: { [key: string]: string } = {};

View File

@@ -1,6 +1,6 @@
import { DownArrowAlt } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -8,7 +8,7 @@ import {
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Permission } from "revolt.js";
import { Message as MessageObject } from "revolt.js/dist/maps/Messages";
import { Message as MessageObject } from "revolt.js";
import styled from "styled-components";
import { openContextMenu } from "preact-context-menu";

View File

@@ -1,7 +1,7 @@
import { UpArrowAlt } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import { decodeTime } from "ulid";
import { Text } from "preact-i18n";

View File

@@ -1,8 +1,7 @@
import { At, Reply as ReplyIcon } from "@styled-icons/boxicons-regular";
import { At } from "@styled-icons/boxicons-regular";
import { File, XCircle } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Channel, Message } from "revolt.js";
import styled from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -1,6 +1,5 @@
import { observer } from "mobx-react-lite";
import { RelationshipStatus } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import styled from "styled-components/macro";
import { Text } from "preact-i18n";
@@ -65,7 +64,7 @@ export default observer(({ channel }: Props) => {
(x) =>
typeof x !== "undefined" &&
x._id !== x.client.user!._id &&
x.relationship !== RelationshipStatus.Blocked,
x.relationship !== "Blocked",
);
if (users.length > 0) {

View File

@@ -1,4 +1,4 @@
import { Embed as EmbedI } from "revolt-api/types/Channels";
import { API } from "revolt.js";
import styles from "./Embed.module.scss";
import classNames from "classnames";
@@ -13,7 +13,7 @@ import Attachment from "../attachments/Attachment";
import EmbedMedia from "./EmbedMedia";
interface Props {
embed: EmbedI;
embed: API.Embed;
}
const MAX_EMBED_WIDTH = 480;
@@ -128,7 +128,7 @@ export default function Embed({ embed }: Props) {
<a
onMouseDown={(ev) =>
(ev.button === 0 || ev.button === 1) &&
openLink(embed.url)
openLink(embed.url!)
}
className={styles.title}>
{embed.title}

View File

@@ -1,14 +1,12 @@
import { Group } from "@styled-icons/boxicons-solid";
import { autorun, reaction } from "mobx";
import { reaction } from "mobx";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { RetrievedInvite } from "revolt-api/types/Invites";
import { Message } from "revolt.js/dist/maps/Messages";
import { Message, API } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { useContext, useEffect, useState } from "preact/hooks";
import { defer } from "../../../../lib/defer";
import { isTouchscreenDevice } from "../../../../lib/isTouchscreenDevice";
import {
@@ -85,9 +83,9 @@ export function EmbedInvite({ code }: Props) {
const [processing, setProcessing] = useState(false);
const [error, setError] = useState<string | undefined>(undefined);
const [joinError, setJoinError] = useState<string | undefined>(undefined);
const [invite, setInvite] = useState<RetrievedInvite | undefined>(
undefined,
);
const [invite, setInvite] = useState<
(API.InviteResponse & { type: "Server" }) | undefined
>(undefined);
useEffect(() => {
if (
@@ -96,7 +94,9 @@ export function EmbedInvite({ code }: Props) {
) {
client
.fetchInvite(code)
.then((data) => setInvite(data))
.then((data) =>
setInvite(data as API.InviteResponse & { type: "Server" }),
)
.catch((err) => setError(takeError(err)));
}
}, [client, code, invite, status]);

View File

@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { JanuaryEmbed } from "revolt-api/types/January";
import { API } from "revolt.js";
import styles from "./Embed.module.scss";
@@ -7,7 +7,7 @@ import { useIntermediate } from "../../../../context/intermediate/Intermediate";
import { useClient } from "../../../../context/revoltjs/RevoltClient";
interface Props {
embed: JanuaryEmbed;
embed: API.Embed;
width?: number;
height: number;
}
@@ -94,7 +94,7 @@ export default function EmbedMedia({ embed, width, height }: Props) {
onClick={() =>
openScreen({
id: "image_viewer",
embed: embed.image,
embed: embed.image!,
})
}
onMouseDown={(ev) =>

View File

@@ -1,12 +1,12 @@
import { LinkExternal } from "@styled-icons/boxicons-regular";
import { EmbedImage } from "revolt-api/types/January";
import { API } from "revolt.js";
import styles from "./Embed.module.scss";
import IconButton from "../../../ui/IconButton";
interface Props {
embed: EmbedImage;
embed: API.Image;
}
export default function EmbedMediaActions({ embed }: Props) {

View File

@@ -1,11 +1,23 @@
import { Shield } from "@styled-icons/boxicons-regular";
import { Badges } from "revolt-api/types/Users";
import styled from "styled-components/macro";
import { Localizer, Text } from "preact-i18n";
import Tooltip from "../Tooltip";
enum Badges {
Developer = 1,
Translator = 2,
Supporter = 4,
ResponsibleDisclosure = 8,
Founder = 16,
PlatformModeration = 32,
ActiveSupporter = 64,
Paw = 128,
EarlyAdopter = 256,
ReservedRelevantJokeBadge1 = 512,
}
const BadgesBase = styled.div`
gap: 8px;
display: flex;

View File

@@ -1,4 +1,4 @@
import { User } from "revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import Checkbox, { CheckboxProps } from "../../ui/Checkbox";

View File

@@ -1,7 +1,7 @@
import { Cog } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link } from "react-router-dom";
import { User } from "revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import styled from "styled-components/macro";
import { openContextMenu } from "preact-context-menu";

View File

@@ -1,4 +1,4 @@
import { User } from "revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import styled from "styled-components/macro";
import { Children } from "../../../types/Preact";

View File

@@ -1,9 +1,7 @@
import { VolumeMute, MicrophoneOff } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
import { Masquerade } from "revolt-api/types/Channels";
import { Presence } from "revolt-api/types/Users";
import { User } from "revolt.js/dist/maps/Users";
import { User, API } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { useApplicationState } from "../../../mobx/State";
@@ -18,17 +16,17 @@ type VoiceStatus = "muted" | "deaf";
interface Props extends IconBaseProps<User> {
status?: boolean;
voice?: VoiceStatus;
masquerade?: Masquerade;
masquerade?: API.Masquerade;
showServerIdentity?: boolean;
}
export function useStatusColour(user?: User) {
const theme = useApplicationState().settings.theme;
return user?.online && user?.status?.presence !== Presence.Invisible
? user?.status?.presence === Presence.Idle
return user?.online && user?.status?.presence !== "Invisible"
? user?.status?.presence === "Idle"
? theme.getVariable("status-away")
: user?.status?.presence === Presence.Busy
: user?.status?.presence === "Busy"
? theme.getVariable("status-busy")
: theme.getVariable("status-online")
: theme.getVariable("status-invisible");
@@ -94,7 +92,7 @@ export default observer(
url =
client.generateFileURL(
override ?? target?.avatar ?? attachment,
override ?? target?.avatar ?? attachment ?? undefined,
{ max_side: 256 },
animate,
) ?? (target ? target.defaultAvatarURL : fallback);

View File

@@ -1,8 +1,6 @@
import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
import { Masquerade } from "revolt-api/types/Channels";
import { User } from "revolt.js/dist/maps/Users";
import { Nullable } from "revolt.js/dist/util/null";
import { User, API } from "revolt.js";
import styled from "styled-components/macro";
import { Text } from "preact-i18n";
@@ -31,7 +29,7 @@ const BotBadge = styled.div`
type UsernameProps = JSX.HTMLAttributes<HTMLElement> & {
user?: User;
prefixAt?: boolean;
masquerade?: Masquerade;
masquerade?: API.Masquerade;
showServerIdentity?: boolean | "both";
};
@@ -116,7 +114,7 @@ export default function UserShort({
user?: User;
size?: number;
prefixAt?: boolean;
masquerade?: Masquerade;
masquerade?: API.Masquerade;
showServerIdentity?: boolean;
}) {
const { openScreen } = useIntermediate();

View File

@@ -1,6 +1,5 @@
import { observer } from "mobx-react-lite";
import { Presence } from "revolt-api/types/Users";
import { User } from "revolt.js/dist/maps/Users";
import { User, API } from "revolt.js";
import { Text } from "preact-i18n";
@@ -25,15 +24,15 @@ export default observer(({ user, tooltip }: Props) => {
return <>{user.status.text}</>;
}
if (user.status?.presence === Presence.Busy) {
if (user.status?.presence === "Busy") {
return <Text id="app.status.busy" />;
}
if (user.status?.presence === Presence.Idle) {
if (user.status?.presence === "Idle") {
return <Text id="app.status.idle" />;
}
if (user.status?.presence === Presence.Invisible) {
if (user.status?.presence === "Invisible") {
return <Text id="app.status.offline" />;
}

View File

@@ -3,7 +3,7 @@ import { Suspense, lazy } from "preact/compat";
const Renderer = lazy(() => import("./Renderer"));
export interface MarkdownProps {
content?: string;
content?: string | null;
disallowBigEmoji?: boolean;
}

View File

@@ -129,7 +129,7 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
const { openLink } = useIntermediate();
if (typeof content === "undefined") return null;
if (content.length === 0) return null;
if (!content || content.length === 0) return null;
// We replace the message with the mention at the time of render.
// We don't care if the mention changes.

View File

@@ -1,9 +1,7 @@
import { X } from "@styled-icons/boxicons-regular";
import { Crown } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Presence } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
import { User } from "revolt.js/dist/maps/Users";
import { User, Channel } from "revolt.js";
import styles from "./Item.module.scss";
import classNames from "classnames";
@@ -64,7 +62,7 @@ export const UserButton = observer((props: UserProps) => {
data-alert={typeof alert === "string"}
data-online={
typeof channel !== "undefined" ||
(user.online && user.status?.presence !== Presence.Invisible)
(user.online && user.status?.presence !== "Invisible")
}
onContextMenu={attachContextMenu("Menu", {
user: user._id,

View File

@@ -5,8 +5,7 @@ import {
Notepad,
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link, Redirect, useLocation, useParams } from "react-router-dom";
import { RelationshipStatus } from "revolt-api/types/Users";
import { Link, useLocation, useParams } from "react-router-dom";
import styled, { css } from "styled-components/macro";
import { Text } from "preact-i18n";
@@ -68,7 +67,7 @@ export default observer(() => {
// ! FIXME: must be a better way
const incoming = [...client.users.values()].filter(
(user) => user?.relationship === RelationshipStatus.Incoming,
(user) => user?.relationship === "Incoming",
);
return (

View File

@@ -2,11 +2,9 @@ import { Plus } from "@styled-icons/boxicons-regular";
import { Cog, Compass } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link, useHistory, useLocation, useParams } from "react-router-dom";
import { RelationshipStatus } from "revolt-api/types/Users";
import styled, { css } from "styled-components/macro";
import { attachContextMenu } from "preact-context-menu";
import { Text } from "preact-i18n";
import ConditionalLink from "../../../lib/ConditionalLink";
import PaintCounter from "../../../lib/PaintCounter";
@@ -248,7 +246,7 @@ export default observer(() => {
const { openScreen } = useIntermediate();
let alertCount = [...client.users.values()].filter(
(x) => x.relationship === RelationshipStatus.Incoming,
(x) => x.relationship === "Incoming",
).length;
const homeActive =

View File

@@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite";
import { Redirect, useParams } from "react-router";
import { Server } from "revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { attachContextMenu } from "preact-context-menu";

View File

@@ -1,6 +1,6 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import { getRenderer } from "../../../lib/renderer/Singleton";

View File

@@ -1,7 +1,6 @@
import { Link } from "react-router-dom";
import { GroupedVirtuoso } from "react-virtuoso";
import { Channel } from "revolt.js/dist/maps/Channels";
import { User } from "revolt.js/dist/maps/Users";
import { Channel, User } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -2,11 +2,7 @@
import { autorun } from "mobx";
import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
import { Role } from "revolt-api/types/Servers";
import { Presence } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { Channel, Server, User, API } from "revolt.js";
import { useContext, useEffect, useState } from "preact/hooks";
@@ -62,7 +58,7 @@ function useEntries(
.map((id) => {
return [id, roles![id], roles![id].rank ?? 0] as [
string,
Role,
API.Role,
number,
];
})
@@ -96,7 +92,7 @@ function useEntries(
const sort = member?.nickname ?? u.username;
const entry = [u, sort] as [User, string];
if (!u.online || u.status?.presence === Presence.Invisible) {
if (!u.online || u.status?.presence === "Invisible") {
categories.offline.push(entry);
} else {
if (isServer) {

View File

@@ -1,5 +1,5 @@
import { Link, useParams } from "react-router-dom";
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
import { Message as MessageI } from "revolt.js";
import styled from "styled-components/macro";
import { Text } from "preact-i18n";

View File

@@ -1,11 +1,11 @@
import { OverrideField } from "revolt-api/types/_common";
import { API } from "revolt.js";
import { Permission } from "revolt.js";
import { PermissionSelect } from "./PermissionSelect";
interface Props {
value: OverrideField | number;
onChange: (v: OverrideField | number) => void;
value: API.OverrideField | number;
onChange: (v: API.OverrideField | number) => void;
filter?: (keyof typeof Permission)[];
}

View File

@@ -1,5 +1,5 @@
import Long from "long";
import { OverrideField } from "revolt-api/types/_common";
import { API } from "revolt.js";
import { Permission } from "revolt.js";
import styled from "styled-components";
@@ -13,8 +13,8 @@ import { OverrideSwitch } from "./OverrideSwitch";
interface PermissionSelectProps {
id: keyof typeof Permission;
permission: number;
value: OverrideField | number;
onChange: (value: OverrideField | number) => void;
value: API.OverrideField | number;
onChange: (value: API.OverrideField | number) => void;
}
type State = "Allow" | "Neutral" | "Deny";

View File

@@ -1,9 +1,9 @@
import { Role } from "revolt-api/types/Servers";
import { API } from "revolt.js";
import Checkbox from "../../ui/Checkbox";
export type RoleOrDefault = (
| Role
| API.Role
| {
name: string;
permissions: number;

View File

@@ -1,13 +1,6 @@
import { Prompt } from "react-router";
import { useHistory } from "react-router-dom";
import type { Attachment } from "revolt-api/types/Autumn";
import { Bot } from "revolt-api/types/Bots";
import { TextChannel, VoiceChannel } from "revolt-api/types/Channels";
import type { EmbedImage } from "revolt-api/types/January";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { API, Channel, Message, Server, User } from "revolt.js";
import { createContext } from "preact";
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
@@ -61,7 +54,11 @@ export type Screen =
| {
type: "create_channel";
target: Server;
cb?: (channel: TextChannel | VoiceChannel) => void;
cb?: (
channel: Channel & {
channel_type: "TextChannel" | "VoiceChannel";
},
) => void;
}
| { type: "create_category"; target: Server }
))
@@ -101,11 +98,11 @@ export type Screen =
omit?: string[];
callback: (users: string[]) => Promise<void>;
}
| { id: "image_viewer"; attachment?: Attachment; embed?: EmbedImage }
| { id: "image_viewer"; attachment?: API.File; embed?: API.Image }
| { id: "channel_info"; channel: Channel }
| { id: "pending_requests"; users: User[] }
| { id: "modify_account"; field: "username" | "email" | "password" }
| { id: "create_bot"; onCreate: (bot: Bot) => void }
| { id: "create_bot"; onCreate: (bot: API.Bot) => void }
| {
id: "server_identity";
server: Server;

View File

@@ -1,5 +1,5 @@
import { useHistory } from "react-router";
import { Server } from "revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import { ulid } from "ulid";
import { Text } from "preact-i18n";
@@ -99,7 +99,6 @@ export function SpecialInputModal(props: SpecialProps) {
callback={async (name) => {
const group = await client.channels.createGroup({
name,
nonce: ulid(),
users: [],
});
@@ -117,7 +116,6 @@ export function SpecialInputModal(props: SpecialProps) {
callback={async (name) => {
const server = await client.servers.createServer({
name,
nonce: ulid(),
});
history.push(`/server/${server._id}`);
@@ -146,7 +144,7 @@ export function SpecialInputModal(props: SpecialProps) {
onClose={onClose}
question={<Text id="app.context_menu.set_custom_status" />}
field={<Text id="app.context_menu.custom_status" />}
defaultValue={client.user?.status?.text}
defaultValue={client.user?.status?.text ?? undefined}
callback={(text) =>
client.users.edit({
status: {
@@ -164,11 +162,8 @@ export function SpecialInputModal(props: SpecialProps) {
onClose={onClose}
question={"Add Friend"}
callback={(username) =>
client
.req(
"PUT",
`/users/${username}/friend` as "/users/id/friend",
)
client.api
.put(`/users/${username as ""}/friend`)
.then(undefined)
}
/>

View File

@@ -16,6 +16,10 @@
h1 {
margin: 0;
}
img {
max-height: 80px;
}
}
&.form {

View File

@@ -1,10 +1,6 @@
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { TextChannel, VoiceChannel } from "revolt-api/types/Channels";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { Channel, Message as MessageI, Server, User } from "revolt.js";
import { ulid } from "ulid";
import styles from "./Prompt.module.scss";
@@ -74,7 +70,11 @@ type SpecialProps = { onClose: () => void } & (
| {
type: "create_channel";
target: Server;
cb?: (channel: TextChannel | VoiceChannel) => void;
cb?: (
channel: Channel & {
channel_type: "TextChannel" | "VoiceChannel";
},
) => void;
}
| { type: "create_category"; target: Server }
);
@@ -429,11 +429,10 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
await props.target.createChannel({
type,
name,
nonce: ulid(),
});
if (props.cb) {
props.cb(channel);
props.cb(channel as any);
} else {
history.push(
`/server/${props.target._id}/channel/${channel._id}`,

View File

@@ -1,6 +1,6 @@
import { X } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import styles from "./ChannelInfo.module.scss";

View File

@@ -1,5 +1,5 @@
import { SubmitHandler, useForm } from "react-hook-form";
import { Bot } from "revolt-api/types/Bots";
import { API } from "revolt.js";
import { Text } from "preact-i18n";
import { useContext, useState } from "preact/hooks";
@@ -13,7 +13,7 @@ import { takeError } from "../../revoltjs/util";
interface Props {
onClose: () => void;
onCreate: (bot: Bot) => void;
onCreate: (bot: API.Bot) => void;
}
interface FormInputs {

View File

@@ -1,6 +1,5 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { Attachment, AttachmentMetadata } from "revolt-api/types/Autumn";
import { EmbedImage } from "revolt-api/types/January";
import { API } from "revolt.js";
import styles from "./ImageViewer.module.scss";
@@ -12,11 +11,11 @@ import { useClient } from "../../revoltjs/RevoltClient";
interface Props {
onClose: () => void;
embed?: EmbedImage;
attachment?: Attachment;
embed?: API.Image;
attachment?: API.File;
}
type ImageMetadata = AttachmentMetadata & { type: "Image" };
type ImageMetadata = API.Metadata & { type: "Image" };
export function ImageViewer({ attachment, embed, onClose }: Props) {
if (attachment && attachment.metadata.type !== "Image") {

View File

@@ -43,19 +43,19 @@ export function ModifyAccountModal({ onClose, field }: Props) {
try {
if (field === "email") {
await client.req("PATCH", "/auth/account/change/email", {
await client.api.patch("/auth/account/change/email", {
current_password: password,
email: new_email,
});
onClose();
} else if (field === "password") {
await client.req("PATCH", "/auth/account/change/password", {
await client.api.patch("/auth/account/change/password", {
current_password: password,
password: new_password,
});
onClose();
} else if (field === "username") {
await client.req("PATCH", "/users/id/username", {
await client.api.patch("/users/@me/username", {
username: new_username,
password,
});

View File

@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { User } from "revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n";

View File

@@ -1,11 +1,12 @@
import { observer } from "mobx-react-lite";
import { Server } from "revolt.js/dist/maps/Servers";
import styled, { css } from "styled-components/macro";
import { Server } from "revolt.js";
import styles from "./ServerIdentityModal.module.scss";
import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import { noop } from "../../../lib/js";
import Button from "../../../components/ui/Button";
import InputBox from "../../../components/ui/InputBox";
import Modal from "../../../components/ui/Modal";
@@ -57,8 +58,12 @@ export const ServerIdentityModal = observer(({ server, onClose }: Props) => {
fileType="avatars"
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) => member.edit({ avatar })}
remove={() => member.edit({ remove: "Avatar" })}
onUpload={(avatar) =>
member.edit({ avatar }).then(noop)
}
remove={() =>
member.edit({ remove: ["Avatar"] }).then(noop)
}
defaultPreview={client.user?.generateAvatarURL(
{
max_side: 256,
@@ -92,7 +97,7 @@ export const ServerIdentityModal = observer(({ server, onClose }: Props) => {
<Button
plain
onClick={() =>
member.edit({ remove: "Nickname" })
member.edit({ remove: ["Nickname"] })
}>
<Text id="app.special.modals.actions.remove" />
</Button>

View File

@@ -1,5 +1,3 @@
import { RelationshipStatus } from "revolt-api/types/Users";
import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n";
import { useState } from "preact/hooks";
@@ -37,7 +35,7 @@ export function UserPicker(props: Props) {
.filter(
(x) =>
x &&
x.relationship === RelationshipStatus.Friend &&
x.relationship === "Friend" &&
!omit.includes(x._id),
)
.map((x) => (

View File

@@ -9,9 +9,7 @@ import {
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link, useHistory } from "react-router-dom";
import { Profile, RelationshipStatus } from "revolt-api/types/Users";
import { UserPermission } from "revolt.js/dist/api/permissions";
import { Route } from "revolt.js/dist/api/routes";
import { UserPermission, API } from "revolt.js";
import styles from "./UserProfile.module.scss";
import { Localizer, Text } from "preact-i18n";
@@ -44,18 +42,18 @@ interface Props {
user_id: string;
dummy?: boolean;
onClose?: () => void;
dummyProfile?: Profile;
dummyProfile?: API.UserProfile;
}
export const UserProfile = observer(
({ user_id, onClose, dummy, dummyProfile }: Props) => {
const { openScreen, writeClipboard } = useIntermediate();
const [profile, setProfile] = useState<undefined | null | Profile>(
undefined,
);
const [profile, setProfile] = useState<
undefined | null | API.UserProfile
>(undefined);
const [mutual, setMutual] = useState<
undefined | null | Route<"GET", "/users/id/mutual">["response"]
undefined | null | API.MutualResponse
>(undefined);
const [isPublicBot, setIsPublicBot] = useState<
undefined | null | boolean
@@ -139,7 +137,11 @@ export const UserProfile = observer(
const backgroundURL =
profile &&
client.generateFileURL(profile.background, { width: 1000 }, true);
client.generateFileURL(
profile.background as any,
{ width: 1000 },
true,
);
const badges = user.badges ?? 0;
const flags = user.flags ?? 0;
@@ -198,7 +200,7 @@ export const UserProfile = observer(
</Button>
</Link>
)}
{user.relationship === RelationshipStatus.Friend && (
{user.relationship === "Friend" && (
<Localizer>
<Tooltip
content={
@@ -214,28 +216,25 @@ export const UserProfile = observer(
</Tooltip>
</Localizer>
)}
{user.relationship === RelationshipStatus.User &&
!dummy && (
<IconButton
onClick={() => {
onClose?.();
history.push(`/settings/profile`);
}}>
<Edit size={28} />
</IconButton>
)}
{user.relationship === "User" && !dummy && (
<IconButton
onClick={() => {
onClose?.();
history.push(`/settings/profile`);
}}>
<Edit size={28} />
</IconButton>
)}
{!user.bot &&
flags != 2 &&
flags != 4 &&
(user.relationship ===
RelationshipStatus.Incoming ||
user.relationship ===
RelationshipStatus.None) && (
(user.relationship === "Incoming" ||
user.relationship === "None") && (
<IconButton onClick={() => user.addFriend()}>
<UserPlus size={28} />
</IconButton>
)}
{user.relationship === RelationshipStatus.Outgoing && (
{user.relationship === "Outgoing" && (
<IconButton onClick={() => user.removeFriend()}>
<UserX size={28} />
</IconButton>
@@ -247,7 +246,7 @@ export const UserProfile = observer(
onClick={() => setTab("profile")}>
<Text id="app.special.popovers.user_profile.profile" />
</div>
{user.relationship !== RelationshipStatus.User && (
{user.relationship !== "User" && (
<>
<div
data-active={tab === "friends"}

View File

@@ -1,7 +1,5 @@
import { Route, Switch, useHistory, useParams } from "react-router-dom";
import { Presence, RelationshipStatus } from "revolt-api/types/Users";
import { Message } from "revolt.js/dist/maps/Messages";
import { User } from "revolt.js/dist/maps/Users";
import { Message, User } from "revolt.js";
import { decodeTime } from "ulid";
import { useCallback, useContext, useEffect } from "preact/hooks";
@@ -210,17 +208,17 @@ function Notifier() {
const relationship = useCallback(
async (user: User) => {
if (client.user?.status?.presence === Presence.Busy) return;
if (client.user?.status?.presence === "Busy") return;
if (!showNotification) return;
let event;
switch (user.relationship) {
case RelationshipStatus.Incoming:
case "Incoming":
event = translate("notifications.sent_request", {
person: user.username,
});
break;
case RelationshipStatus.Friend:
case "Friend":
event = translate("notifications.now_friends", {
person: user.username,
});

View File

@@ -50,7 +50,7 @@ export default observer(({ children }: Props) => {
useEffect(() => {
if (navigator.onLine) {
state.config.createClient().req("GET", "/").then(state.config.set);
state.config.createClient().api.get("/").then(state.config.set);
}
}, []);
@@ -79,7 +79,7 @@ export default observer(({ children }: Props) => {
}
}, [state.auth.getSession()]);
useEffect(() => registerEvents(state.auth, setStatus, client), [client]);
useEffect(() => registerEvents(state, setStatus, client), [client]);
if (!loaded || status === ClientStatus.LOADING) {
return <Preloader type="spinner" />;

View File

@@ -1,7 +1,7 @@
/**
* This file monitors the message cache to delete any queued messages that have already sent.
*/
import { Message } from "revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { useContext, useEffect } from "preact/hooks";

View File

@@ -1,17 +1,16 @@
import { Client } from "revolt.js/dist";
import { Server } from "revolt.js/dist/maps/Servers";
import { Client, Server } from "revolt.js";
import { StateUpdater } from "preact/hooks";
import { deleteRenderer } from "../../lib/renderer/Singleton";
import Auth from "../../mobx/stores/Auth";
import State from "../../mobx/State";
import { resetMemberSidebarFetched } from "../../components/navigation/right/MemberSidebar";
import { ClientStatus } from "./RevoltClient";
export function registerEvents(
auth: Auth,
state: State,
setStatus: StateUpdater<ClientStatus>,
client: Client,
) {
@@ -28,7 +27,8 @@ export function registerEvents(
},
logout: () => {
auth.logout();
state.auth.logout();
state.reset();
setStatus(ClientStatus.READY);
},

View File

@@ -1,4 +1,4 @@
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import { Text } from "preact-i18n";

View File

@@ -12,13 +12,8 @@ import {
} from "@styled-icons/boxicons-regular";
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
import { useHistory } from "react-router-dom";
import { Attachment } from "revolt-api/types/Autumn";
import { Presence, RelationshipStatus } from "revolt-api/types/Users";
import { Channel, Message, Server, User, API } from "revolt.js";
import { Permission, UserPermission } from "revolt.js/dist/api/permissions";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import {
ContextMenuWithData,
@@ -56,7 +51,7 @@ interface ContextMenuData {
server_list?: string;
channel?: string;
message?: Message;
attachment?: Attachment;
attachment?: API.File;
unread?: boolean;
queued?: QueuedMessage;
@@ -78,9 +73,9 @@ type Action =
| { action: "quote_message"; content: string }
| { action: "edit_message"; id: string }
| { action: "delete_message"; target: Message }
| { action: "open_file"; attachment: Attachment }
| { action: "save_file"; attachment: Attachment }
| { action: "copy_file_link"; attachment: Attachment }
| { action: "open_file"; attachment: API.File }
| { action: "save_file"; attachment: API.File }
| { action: "copy_file_link"; attachment: API.File }
| { action: "open_link"; link: string }
| { action: "copy_link"; link: string }
| { action: "remove_member"; channel: Channel; user: User }
@@ -93,7 +88,7 @@ type Action =
| { action: "add_friend"; user: User }
| { action: "remove_friend"; user: User }
| { action: "cancel_friend"; user: User }
| { action: "set_presence"; presence: Presence }
| { action: "set_presence"; presence: API.Presence }
| { action: "set_status" }
| { action: "clear_status" }
| { action: "create_channel"; target: Server }
@@ -588,29 +583,29 @@ export default function ContextMenus() {
if (!user.bot) {
let actions: Action["action"][];
switch (user.relationship) {
case RelationshipStatus.User:
case "User":
actions = [];
break;
case RelationshipStatus.Friend:
case "Friend":
actions = ["remove_friend", "block_user"];
break;
case RelationshipStatus.Incoming:
case "Incoming":
actions = [
"add_friend",
"cancel_friend",
"block_user",
];
break;
case RelationshipStatus.Outgoing:
case "Outgoing":
actions = ["cancel_friend", "block_user"];
break;
case RelationshipStatus.Blocked:
case "Blocked":
actions = ["unblock_user"];
break;
case RelationshipStatus.BlockedOther:
case "BlockedOther":
actions = ["block_user"];
break;
case RelationshipStatus.None:
case "None":
default:
if (
(user.flags && 2) ||
@@ -1047,7 +1042,7 @@ export default function ContextMenus() {
<MenuItem
data={{
action: "set_presence",
presence: Presence.Online,
presence: "Online",
}}
disabled={!isOnline}>
<div className="indicator online" />
@@ -1056,7 +1051,7 @@ export default function ContextMenus() {
<MenuItem
data={{
action: "set_presence",
presence: Presence.Idle,
presence: "Idle",
}}
disabled={!isOnline}>
<div className="indicator idle" />
@@ -1065,7 +1060,7 @@ export default function ContextMenus() {
<MenuItem
data={{
action: "set_presence",
presence: Presence.Busy,
presence: "Busy",
}}
disabled={!isOnline}>
<div className="indicator busy" />
@@ -1074,7 +1069,7 @@ export default function ContextMenus() {
<MenuItem
data={{
action: "set_presence",
presence: Presence.Invisible,
presence: "Invisible",
}}
disabled={!isOnline}>
<div className="indicator invisible" />

View File

@@ -1,7 +1,7 @@
// @ts-expect-error No typings.
import stringify from "json-stringify-deterministic";
import localforage from "localforage";
import { makeAutoObservable, reaction } from "mobx";
import { makeAutoObservable, reaction, runInAction } from "mobx";
import { Client } from "revolt.js";
import { reportError } from "../lib/ErrorBoundary";
@@ -59,6 +59,7 @@ export default class State {
this.sync = new Sync(this);
makeAutoObservable(this);
this.register();
this.setDisabled = this.setDisabled.bind(this);
}
@@ -159,10 +160,12 @@ export default class State {
}
if (Object.keys(obj).length > 0) {
client.syncSetSettings(
obj as any,
revision,
);
if (client.websocket.connected) {
client.syncSetSettings(
obj as any,
revision,
);
}
}
break;
}
@@ -173,12 +176,14 @@ export default class State {
}
this.sync.setRevision(id, revision);
client.syncSetSettings(
(
store as unknown as Syncable
).toSyncable(),
revision,
);
if (client.websocket.connected) {
client.syncSetSettings(
(
store as unknown as Syncable
).toSyncable(),
revision,
);
}
}
}
}
@@ -229,6 +234,24 @@ export default class State {
// Dump stores back to disk.
await this.save();
}
/**
* Reset known state values.
*/
reset() {
runInAction(() => {
this.draft = new Draft();
this.experiments = new Experiments();
this.layout = new Layout();
this.notifications = new NotificationOptions();
this.queue = new MessageQueue();
this.settings = new Settings();
this.sync = new Sync(this);
this.persistent = [];
this.register();
});
}
}
var state: State;

View File

@@ -1,5 +1,5 @@
import { runInAction } from "mobx";
import { Session } from "revolt-api/types/Auth";
import { API } from "revolt.js";
import { Language } from "../../context/Locale";
import {
@@ -63,7 +63,7 @@ export interface LegacySyncOptions {
export interface LegacyAuthState {
accounts: {
[key: string]: {
session: Session;
session: API.Session;
};
};
active?: string;

View File

@@ -1,5 +1,5 @@
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
import { Session } from "revolt-api/types/Auth";
import { API } from "revolt.js";
import { Nullable } from "revolt.js/dist/util/null";
import { mapToRecord } from "../../lib/conversion";
@@ -8,7 +8,7 @@ import Persistent from "../interfaces/Persistent";
import Store from "../interfaces/Store";
interface Account {
session: Session;
session: API.Session;
}
export interface Data {
@@ -82,7 +82,7 @@ export default class Auth implements Store, Persistent<Data> {
* Add a new session to the auth manager.
* @param session Session
*/
@action setSession(session: Session) {
@action setSession(session: API.Session) {
this.sessions.set(session.user_id, { session });
this.current = session.user_id;
}

View File

@@ -1,5 +1,4 @@
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
import { Presence, RelationshipStatus } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
@@ -113,7 +112,7 @@ export default class NotificationOptions
*/
shouldNotify(message: Message) {
// Make sure the author is not blocked.
if (message.author?.relationship === RelationshipStatus.Blocked) {
if (message.author?.relationship === "Blocked") {
return false;
}
@@ -124,7 +123,7 @@ export default class NotificationOptions
}
// Check whether we are busy.
if (user.status?.presence === Presence.Busy) {
if (user.status?.presence === "Busy") {
return false;
}

View File

@@ -1,5 +1,5 @@
import { action, computed, makeAutoObservable } from "mobx";
import { RevoltConfiguration } from "revolt-api/types/Core";
import { API } from "revolt.js";
import { Client } from "revolt.js";
import { Nullable } from "revolt.js/dist/util/null";
@@ -11,9 +11,9 @@ import Store from "../interfaces/Store";
* Stores server configuration data.
*/
export default class ServerConfig
implements Store, Persistent<RevoltConfiguration>
implements Store, Persistent<API.RevoltConfig>
{
private config: Nullable<RevoltConfiguration>;
private config: Nullable<API.RevoltConfig>;
/**
* Construct new ServerConfig store.
@@ -32,7 +32,7 @@ export default class ServerConfig
return JSON.parse(JSON.stringify(this.config));
}
@action hydrate(data: RevoltConfiguration) {
@action hydrate(data: API.RevoltConfig) {
this.config = data ?? null;
}
@@ -68,7 +68,7 @@ export default class ServerConfig
* Set server configuration.
* @param config Server configuration
*/
@action set(config: RevoltConfiguration) {
@action set(config: API.RevoltConfig) {
this.config = config;
}
}

View File

@@ -7,7 +7,6 @@ import {
runInAction,
} from "mobx";
import { Client } from "revolt.js";
import { UserSettings } from "revolt-api/types/Sync";
import { mapToRecord } from "../../lib/conversion";
@@ -104,7 +103,7 @@ export default class Sync implements Store, Persistent<Data> {
return this.revision.get(key);
}
@action apply(data: UserSettings) {
@action apply(data: Record<string, [number, string]>) {
const tryRead = (key: string) => {
if (key in data) {
const revision = data[key][0];

View File

@@ -149,9 +149,9 @@ const TextChannel = observer(({ channel }: { channel: ChannelI }) => {
// Mark channel as read.
useEffect(() => {
setLastId(
channel.unread
(channel.unread
? channel.client.unreads?.getUnread(channel._id)?.last_id
: undefined ?? undefined,
: undefined) ?? undefined,
);
const checkUnread = () =>

View File

@@ -2,8 +2,7 @@
import { X } from "@styled-icons/boxicons-regular";
import isEqual from "lodash.isequal";
import { observer } from "mobx-react-lite";
import { Masquerade } from "revolt-api/types/Channels";
import { RelationshipStatus } from "revolt-api/types/Users";
import { API } from "revolt.js";
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
import { Nullable } from "revolt.js/dist/util/null";
import styled from "styled-components/macro";
@@ -99,10 +98,10 @@ export default observer(({ last_id, renderer, highlight }: Props) => {
function compare(
current: string,
curAuthor: string,
currentMasq: Nullable<Masquerade>,
currentMasq: Nullable<API.Masquerade>,
previous: string,
prevAuthor: string,
previousMasq: Nullable<Masquerade>,
previousMasq: Nullable<API.Masquerade>,
) {
head = false;
const atime = decodeTime(current),
@@ -172,9 +171,7 @@ export default observer(({ last_id, renderer, highlight }: Props) => {
highlight={highlight === message._id}
/>,
);
} else if (
message.author?.relationship === RelationshipStatus.Blocked
) {
} else if (message.author?.relationship === "Blocked") {
blocked++;
} else {
if (blocked > 0) pushBlocked();

View File

@@ -2,7 +2,6 @@ import { X, Plus } from "@styled-icons/boxicons-regular";
import { PhoneCall, Envelope, UserX } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { RelationshipStatus } from "revolt-api/types/Users";
import { User } from "revolt.js/dist/maps/Users";
import styles from "./Friend.module.scss";
@@ -33,7 +32,7 @@ export const Friend = observer(({ user }: Props) => {
const actions: Children[] = [];
let subtext: Children = null;
if (user.relationship === RelationshipStatus.Friend) {
if (user.relationship === "Friend") {
subtext = <UserStatus user={user} />;
actions.push(
<>
@@ -70,7 +69,7 @@ export const Friend = observer(({ user }: Props) => {
);
}
if (user.relationship === RelationshipStatus.Incoming) {
if (user.relationship === "Incoming") {
actions.push(
<IconButton
type="circle"
@@ -83,14 +82,14 @@ export const Friend = observer(({ user }: Props) => {
subtext = <Text id="app.special.friends.incoming" />;
}
if (user.relationship === RelationshipStatus.Outgoing) {
if (user.relationship === "Outgoing") {
subtext = <Text id="app.special.friends.outgoing" />;
}
if (
user.relationship === RelationshipStatus.Friend ||
user.relationship === RelationshipStatus.Outgoing ||
user.relationship === RelationshipStatus.Incoming
user.relationship === "Friend" ||
user.relationship === "Outgoing" ||
user.relationship === "Incoming"
) {
actions.push(
<IconButton
@@ -103,7 +102,7 @@ export const Friend = observer(({ user }: Props) => {
onClick={(ev) =>
stopPropagation(
ev,
user.relationship === RelationshipStatus.Friend
user.relationship === "Friend"
? openScreen({
id: "special_prompt",
type: "unfriend_user",
@@ -117,7 +116,7 @@ export const Friend = observer(({ user }: Props) => {
);
}
if (user.relationship === RelationshipStatus.Blocked) {
if (user.relationship === "Blocked") {
actions.push(
<IconButton
type="circle"

View File

@@ -1,9 +1,7 @@
import { ChevronRight } from "@styled-icons/boxicons-regular";
import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { RelationshipStatus, Presence } from "revolt-api/types/Users";
import { User } from "revolt.js/dist/maps/Users";
import styled, { css } from "styled-components/macro";
import styles from "./Friend.module.scss";
import classNames from "classnames";
@@ -31,37 +29,32 @@ export default observer(() => {
const users = [...client.users.values()];
users.sort((a, b) => a.username.localeCompare(b.username));
const friends = users.filter(
(x) => x.relationship === RelationshipStatus.Friend,
);
const friends = users.filter((x) => x.relationship === "Friend");
const lists = [
[
"",
users.filter((x) => x.relationship === RelationshipStatus.Incoming),
],
["", users.filter((x) => x.relationship === "Incoming")],
[
"app.special.friends.sent",
users.filter((x) => x.relationship === RelationshipStatus.Outgoing),
users.filter((x) => x.relationship === "Outgoing"),
"outgoing",
],
[
"app.status.online",
friends.filter(
(x) => x.online && x.status?.presence !== Presence.Invisible,
(x) => x.online && x.status?.presence !== "Invisible",
),
"online",
],
[
"app.status.offline",
friends.filter(
(x) => !x.online || x.status?.presence === Presence.Invisible,
(x) => !x.online || x.status?.presence === "Invisible",
),
"offline",
],
[
"app.special.friends.blocked",
users.filter((x) => x.relationship === RelationshipStatus.Blocked),
users.filter((x) => x.relationship === "Blocked"),
"blocked",
],
] as [string, User[], string][];

View File

@@ -1,7 +1,7 @@
import { ArrowBack } from "@styled-icons/boxicons-regular";
import { autorun } from "mobx";
import { Redirect, useHistory, useParams } from "react-router-dom";
import { RetrievedInvite } from "revolt-api/types/Invites";
import { API } from "revolt.js";
import styles from "./Invite.module.scss";
import { Text } from "preact-i18n";
@@ -36,7 +36,7 @@ export default function Invite() {
const { code } = useParams<{ code: string }>();
const [processing, setProcessing] = useState(false);
const [error, setError] = useState<string | undefined>(undefined);
const [invite, setInvite] = useState<RetrievedInvite | undefined>(
const [invite, setInvite] = useState<API.InviteResponse | undefined>(
undefined,
);
@@ -92,6 +92,8 @@ export default function Invite() {
);
}
if (invite.type === "Group") return <h1>unimplemented</h1>;
return (
<div
className={styles.invite}

View File

@@ -1,6 +1,5 @@
import { useParams } from "react-router-dom";
import { Permission } from "revolt.js";
import { Route } from "revolt.js/dist/api/routes";
import { API, Permission } from "revolt.js";
import styled from "styled-components/macro";
import { useEffect, useState } from "preact/hooks";
@@ -37,8 +36,7 @@ const Option = styled.div`
export default function InviteBot() {
const { id } = useParams<{ id: string }>();
const client = useClient();
const [data, setData] =
useState<Route<"GET", "/bots/id/invite">["response"]>();
const [data, setData] = useState<API.PublicBot>();
useEffect(() => {
client.bots.fetchPublic(id).then(setData);

View File

@@ -1,6 +1,5 @@
import { detect } from "detect-browser";
import { Session } from "revolt-api/types/Auth";
import { Client } from "revolt.js";
import { API } from "revolt.js";
import { useApplicationState } from "../../../mobx/State";
@@ -44,25 +43,26 @@ export function FormLogin() {
// This should be replaced in the future.
const client = state.config.createClient();
await client.fetchConfiguration();
const session = (await client.req(
"POST",
"/auth/session/login",
{ ...data, friendly_name },
)) as unknown as Session;
const session = await client.api.post("/auth/session/login", {
...data,
friendly_name,
});
client.session = session;
(client as any).Axios.defaults.headers = {
"x-session-token": session?.token,
};
async function login() {
state.auth.setSession(session);
if (session.result !== "Success") {
alert("unsupported!");
return;
}
const { onboarding } = await client.req(
"GET",
"/onboard/hello",
);
const s = session;
client.session = session;
(client as any).$updateHeaders();
async function login() {
state.auth.setSession(s);
}
const { onboarding } = await client.api.get("/onboard/hello");
if (onboarding) {
openScreen({

View File

@@ -16,7 +16,7 @@ export function FormSendReset() {
<Form
page="send_reset"
callback={async (data) => {
await client.req("POST", "/auth/account/reset_password", data);
await client.api.post("/auth/account/reset_password", data);
}}
/>
);
@@ -32,7 +32,7 @@ export function FormReset() {
<Form
page="reset"
callback={async (data) => {
await client.req("PATCH", "/auth/account/reset_password", {
await client.api.patch("/auth/account/reset_password", {
token,
...data,
});

View File

@@ -20,7 +20,7 @@ export function FormResend() {
<Form
page="resend"
callback={async (data) => {
await client.req("POST", "/auth/account/reverify", data);
await client.api.post("/auth/account/reverify", data);
}}
/>
);
@@ -34,11 +34,8 @@ export function FormVerify() {
const history = useHistory();
useEffect(() => {
client
.req(
"POST",
`/auth/account/verify/${token}` as "/auth/account/verify/:code",
)
client.api
.post(`/auth/account/verify/${token as ""}`)
.then(() => history.push("/login"))
.catch((err) => setError(takeError(err)));
// eslint-disable-next-line

View File

@@ -337,7 +337,9 @@ export default observer(() => {
<Trash
size={24}
onClick={() =>
client.users.edit({ remove: "StatusText" })
client.users.edit({
remove: ["StatusText"],
})
}
/>
)}

View File

@@ -69,7 +69,7 @@ export default observer(({ channel }: Props) => {
{ max_side: 256 },
true,
)}
remove={() => channel.edit({ remove: "Icon" })}
remove={() => channel.edit({ remove: ["Icon"] })}
defaultPreview={
channel.channel_type === "Group"
? "/assets/group.png"

View File

@@ -1,7 +1,6 @@
import isEqual from "lodash.isequal";
import { observer } from "mobx-react-lite";
import { OverrideField } from "revolt-api/types/_common";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel, API } from "revolt.js";
import { useLayoutEffect, useState } from "preact/hooks";
@@ -42,7 +41,7 @@ export default observer(({ channel }: Props) => {
// Keep track of whatever role we're editing right now.
const [selected, setSelected] = useState("default");
const [value, setValue] = useState<OverrideField | number | undefined>(
const [value, setValue] = useState<API.OverrideField | number | undefined>(
undefined,
);
const currentPermission = currentRoles.find(
@@ -64,10 +63,10 @@ export default observer(({ channel }: Props) => {
selected,
typeof currentValue === "number"
? currentValue
: {
: ({
allow: currentValue.a,
deny: currentValue.d,
},
} as any),
);
}

View File

@@ -1,4 +1,4 @@
import { At, Key, Block, ListOl } from "@styled-icons/boxicons-regular";
import { At, Key, Block } from "@styled-icons/boxicons-regular";
import {
Envelope,
HelpCircle,
@@ -8,7 +8,7 @@ import {
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { Profile } from "revolt-api/types/Users";
import { API } from "revolt.js";
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
@@ -37,7 +37,9 @@ export const Account = observer(() => {
const [email, setEmail] = useState("...");
const [revealEmail, setRevealEmail] = useState(false);
const [profile, setProfile] = useState<undefined | Profile>(undefined);
const [profile, setProfile] = useState<undefined | API.UserProfile>(
undefined,
);
const history = useHistory();
function switchPage(to: string) {
@@ -46,8 +48,8 @@ export const Account = observer(() => {
useEffect(() => {
if (email === "..." && status === ClientStatus.ONLINE) {
client
.req("GET", "/auth/account")
client.api
.get("/auth/account/")
.then((account) => setEmail(account.email));
}

View File

@@ -1,9 +1,9 @@
// ! FIXME: this code is garbage, need to replace
import { Key, Clipboard, Globe, Plus } from "@styled-icons/boxicons-regular";
import { LockAlt, HelpCircle } from "@styled-icons/boxicons-solid";
import type { AxiosError } from "axios";
import { observer } from "mobx-react-lite";
import { Bot } from "revolt-api/types/Bots";
import { Profile as ProfileI } from "revolt-api/types/Users";
import { API } from "revolt.js";
import { User } from "revolt.js/dist/maps/Users";
import styled from "styled-components/macro";
@@ -43,7 +43,7 @@ interface Changes {
name?: string;
public?: boolean;
interactions_url?: string;
remove?: "InteractionsURL";
remove?: "InteractionsURL"[];
}
const BotBadge = styled.div`
@@ -62,7 +62,7 @@ const BotBadge = styled.div`
`;
interface Props {
bot: Bot;
bot: API.Bot;
onDelete(): void;
onUpdate(changes: Changes): void;
}
@@ -75,7 +75,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
_id: bot._id,
username: user.username,
public: bot.public,
interactions_url: bot.interactions_url,
interactions_url: bot.interactions_url as any,
});
const [error, setError] = useState<string | JSX.Element>("");
const [saving, setSaving] = useState(false);
@@ -87,23 +87,21 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
useState<HTMLInputElement | null>(null);
const { writeClipboard, openScreen } = useIntermediate();
const [profile, setProfile] = useState<undefined | ProfileI>(undefined);
const [profile, setProfile] = useState<undefined | API.UserProfile>(
undefined,
);
const refreshProfile = useCallback(() => {
client
.request(
"GET",
`/users/${bot._id}/profile` as "/users/id/profile",
{
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers["x-user-id"];
delete headers["x-session-token"];
return data;
},
client.api
.get(`/users/${bot._id as ""}/profile`, undefined, {
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers?.["x-user-id"];
delete headers?.["x-session-token"];
return data;
},
)
})
.then((profile) => setProfile(profile ?? {}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user, setProfile]);
@@ -122,14 +120,14 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
const changes: Changes = {};
if (data.username !== user!.username) changes.name = data.username;
if (data.public !== bot.public) changes.public = data.public;
if (data.interactions_url === "") changes.remove = "InteractionsURL";
if (data.interactions_url === "") changes.remove = ["InteractionsURL"];
else if (data.interactions_url !== bot.interactions_url)
changes.interactions_url = data.interactions_url;
setSaving(true);
setError("");
try {
await client.bots.edit(bot._id, changes);
if (changed) await editBotContent(profile?.content);
if (changed) await editBotContent(profile?.content ?? undefined);
onUpdate(changes);
setChanged(false);
setEditMode(false);
@@ -152,19 +150,22 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
async function editBotAvatar(avatar?: string) {
setSaving(true);
setError("");
await client.request("PATCH", "/users/id", {
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers["x-user-id"];
delete headers["x-session-token"];
return data;
await client.api.patch(
"/users/@me",
avatar ? { avatar } : { remove: ["Avatar"] },
{
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers?.["x-user-id"];
delete headers?.["x-session-token"];
return data;
},
},
data: JSON.stringify(avatar ? { avatar } : { remove: "Avatar" }),
});
);
const res = await client.bots.fetch(bot._id);
if (!avatar) res.user.update({}, "Avatar");
if (!avatar) res.user.update({}, ["Avatar"]);
setUser(res.user);
setSaving(false);
}
@@ -172,20 +173,21 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
async function editBotBackground(background?: string) {
setSaving(true);
setError("");
await client.request("PATCH", "/users/id", {
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers["x-user-id"];
delete headers["x-session-token"];
return data;
await client.api.patch(
"/users/@me",
background
? { profile: { background } }
: { remove: ["ProfileBackground"] },
{
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers?.["x-user-id"];
delete headers?.["x-session-token"];
return data;
},
},
data: JSON.stringify(
background
? { profile: { background } }
: { remove: "ProfileBackground" },
),
});
);
if (!background) setProfile({ ...profile, background: undefined });
else refreshProfile();
@@ -195,20 +197,19 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
async function editBotContent(content?: string) {
setSaving(true);
setError("");
await client.request("PATCH", "/users/id", {
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers["x-user-id"];
delete headers["x-session-token"];
return data;
await client.api.patch(
"/users/@me",
content ? { profile: { content } } : { remove: ["ProfileContent"] },
{
headers: { "x-bot-token": bot.token },
transformRequest: (data, headers) => {
// Remove user headers for this request
delete headers?.["x-user-id"];
delete headers?.["x-session-token"];
return data;
},
},
data: JSON.stringify(
content
? { profile: { content } }
: { remove: "ProfileContent" },
),
});
);
if (!content) setProfile({ ...profile, content: undefined });
else refreshProfile();
@@ -333,7 +334,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
_id: bot._id,
username: user!.username,
public: bot.public,
interactions_url: bot.interactions_url,
interactions_url: bot.interactions_url as any,
});
usernameRef!.value = user!.username;
interactionsRef!.value = bot.interactions_url || "";
@@ -521,7 +522,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
export const MyBots = observer(() => {
const client = useClient();
const [bots, setBots] = useState<Bot[] | undefined>(undefined);
const [bots, setBots] = useState<API.Bot[] | undefined>(undefined);
useEffect(() => {
client.bots.fetchOwned().then(({ bots }) => setBots(bots));
@@ -582,7 +583,7 @@ export const MyBots = observer(() => {
changes.interactions_url;
if (
changes.remove ===
"InteractionsURL"
["InteractionsURL"]
)
x.interactions_url = undefined;
}

View File

@@ -81,7 +81,7 @@ export const Notifications = observer(() => {
// tell the server we just subscribed
const json = sub.toJSON();
if (json.keys) {
client.req("POST", "/push/subscribe", {
client.api.post("/push/subscribe", {
endpoint: sub.endpoint,
...(json.keys as {
p256dh: string;
@@ -96,7 +96,7 @@ export const Notifications = observer(() => {
sub?.unsubscribe();
setPushEnabled(false);
client.req("POST", "/push/unsubscribe");
client.api.post("/push/unsubscribe");
}
}
} catch (err) {

View File

@@ -1,7 +1,7 @@
import { Markdown } from "@styled-icons/boxicons-logos";
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { Profile as ProfileI } from "revolt-api/types/Users";
import { API } from "revolt.js";
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
@@ -30,7 +30,9 @@ export const Profile = observer(() => {
const client = useClient();
const history = useHistory();
const [profile, setProfile] = useState<undefined | ProfileI>(undefined);
const [profile, setProfile] = useState<undefined | API.UserProfile>(
undefined,
);
// ! FIXME: temporary solution
// ! we should just announce profile changes through WS
@@ -103,7 +105,7 @@ export const Profile = observer(() => {
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) => client.users.edit({ avatar })}
remove={() => client.users.edit({ remove: "Avatar" })}
remove={() => client.users.edit({ remove: ["Avatar"] })}
defaultPreview={client.user!.generateAvatarURL(
{ max_side: 256 },
true,
@@ -132,7 +134,7 @@ export const Profile = observer(() => {
}}
remove={async () => {
await client.users.edit({
remove: "ProfileBackground",
remove: ["ProfileBackground"],
});
setProfile({ ...profile, background: undefined });
}}

View File

@@ -11,7 +11,7 @@ import {
} from "@styled-icons/simple-icons";
import relativeTime from "dayjs/plugin/relativeTime";
import { useHistory } from "react-router-dom";
import { SessionInfo } from "revolt-api/types/Auth";
import { API } from "revolt.js";
import { decodeTime } from "ulid";
import styles from "./Panes.module.scss";
@@ -33,7 +33,7 @@ export function Sessions() {
const deviceId =
typeof client.session === "object" ? client.session._id : undefined;
const [sessions, setSessions] = useState<SessionInfo[] | undefined>(
const [sessions, setSessions] = useState<API.SessionInfo[] | undefined>(
undefined,
);
const [attemptingDelete, setDelete] = useState<string[]>([]);
@@ -44,7 +44,7 @@ export function Sessions() {
}
useEffect(() => {
client.req("GET", "/auth/session/all").then((data) => {
client.api.get("/auth/session/all").then((data) => {
data.sort(
(a, b) =>
(b._id === deviceId ? 1 : 0) - (a._id === deviceId ? 1 : 0),
@@ -61,7 +61,7 @@ export function Sessions() {
);
}
function getIcon(session: SessionInfo) {
function getIcon(session: API.SessionInfo) {
const name = session.name;
switch (true) {
case /firefox/i.test(name):
@@ -83,7 +83,7 @@ export function Sessions() {
}
}
function getSystemIcon(session: SessionInfo) {
function getSystemIcon(session: API.SessionInfo) {
const name = session.name;
switch (true) {
case /linux/i.test(name):
@@ -187,9 +187,10 @@ export function Sessions() {
...attemptingDelete,
session._id,
]);
await client.req(
"DELETE",
`/auth/session/${session._id}` as "/auth/session/id",
await client.api.delete(
`/auth/session/${
session._id as ""
}`,
);
setSessions(
sessions?.filter(
@@ -222,10 +223,7 @@ export function Sessions() {
setDelete(del);
for (const id of del) {
await client.req(
"DELETE",
`/auth/session/${id}` as "/auth/session/id",
);
await client.api.delete(`/auth/session/${id as ""}`);
}
setSessions(sessions.filter((x) => x._id === deviceId));

View File

@@ -1,9 +1,7 @@
import { XCircle } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Virtuoso } from "react-virtuoso";
import { Ban } from "revolt-api/types/Servers";
import { User } from "revolt-api/types/Users";
import { Route } from "revolt.js/dist/api/routes";
import { API } from "revolt.js";
import { Server } from "revolt.js/dist/maps/Servers";
import styles from "./Panes.module.scss";
@@ -15,8 +13,8 @@ import IconButton from "../../../components/ui/IconButton";
import Preloader from "../../../components/ui/Preloader";
interface InnerProps {
ban: Ban;
users: Pick<User, "username" | "avatar" | "_id">[];
ban: API.ServerBan;
users: Pick<API.User, "username" | "avatar" | "_id">[];
server: Server;
removeSelf: () => void;
}
@@ -53,9 +51,7 @@ interface Props {
}
export const Bans = observer(({ server }: Props) => {
const [data, setData] = useState<
Route<"GET", "/servers/id/bans">["response"] | undefined
>(undefined);
const [data, setData] = useState<API.BanListResult | undefined>(undefined);
useEffect(() => {
server.fetchBans().then(setData);

View File

@@ -1,9 +1,7 @@
import { Plus, X } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { DragDropContext } from "react-beautiful-dnd";
import { TextChannel, VoiceChannel } from "revolt-api/types/Channels";
import { Category } from "revolt-api/types/Servers";
import { Server } from "revolt.js/dist/maps/Servers";
import { Channel, Server, API } from "revolt.js";
import styled, { css } from "styled-components/macro";
import { ulid } from "ulid";
@@ -135,7 +133,7 @@ interface Props {
export const Categories = observer(({ server }: Props) => {
const [status, setStatus] = useState<EditStatus>("saved");
const [categories, setCategories] = useState<Category[]>(
const [categories, setCategories] = useState<API.Category[]>(
server.categories ?? [],
);
@@ -327,12 +325,14 @@ function ListElement({
addChannel,
draggable,
}: {
category: Category;
category: API.Category;
server: Server;
index: number;
setTitle?: (title: string) => void;
deleteSelf?: () => void;
addChannel: (channel: TextChannel | VoiceChannel) => void;
addChannel: (
channel: Channel & { channel_type: "TextChannel" | "VoiceChannel" },
) => void;
draggable?: boolean;
}) {
const { openScreen } = useIntermediate();

View File

@@ -1,8 +1,7 @@
import { XCircle } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Virtuoso } from "react-virtuoso";
import { Invite, ServerInvite } from "revolt-api/types/Invites";
import { Server } from "revolt.js/dist/maps/Servers";
import { API, Server } from "revolt.js";
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
@@ -16,7 +15,7 @@ import IconButton from "../../../components/ui/IconButton";
import Preloader from "../../../components/ui/Preloader";
interface InnerProps {
invite: Invite;
invite: API.Invite;
server: Server;
removeSelf: () => void;
}
@@ -52,12 +51,10 @@ interface Props {
}
export const Invites = ({ server }: Props) => {
const [invites, setInvites] = useState<ServerInvite[] | undefined>(
undefined,
);
const [invites, setInvites] = useState<API.Invite[] | undefined>(undefined);
useEffect(() => {
server.fetchInvites().then(setInvites);
server.fetchInvites().then((v) => setInvites(v));
}, [server, setInvites]);
return (

View File

@@ -8,6 +8,7 @@ import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
import { noop } from "../../../lib/js";
import { FileUploader } from "../../../context/revoltjs/FileUploads";
import { getChannelName } from "../../../context/revoltjs/util";
@@ -60,9 +61,9 @@ export const Overview = observer(({ server }: Props) => {
fileType="icons"
behaviour="upload"
maxFileSize={2_500_000}
onUpload={(icon) => server.edit({ icon })}
onUpload={(icon) => server.edit({ icon }).then(noop)}
previewURL={server.generateIconURL({ max_side: 256 }, true)}
remove={() => server.edit({ remove: "Icon" })}
remove={() => server.edit({ remove: ["Icon"] }).then(noop)}
/>
<div className={styles.name}>
<h3>
@@ -117,9 +118,9 @@ export const Overview = observer(({ server }: Props) => {
fileType="banners"
behaviour="upload"
maxFileSize={6_000_000}
onUpload={(banner) => server.edit({ banner })}
onUpload={(banner) => server.edit({ banner }).then(noop)}
previewURL={server.generateBannerURL({ width: 1000 }, true)}
remove={() => server.edit({ remove: "Banner" })}
remove={() => server.edit({ remove: ["Banner"] }).then(noop)}
/>
<hr />
<h3>