Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Showing
with 731 additions and 1089 deletions
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { Channels, Servers, Users } from "revolt.js/dist/api/objects"; 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 { ulid } from "ulid"; import { ulid } from "ulid";
import styles from "./Prompt.module.scss"; import styles from "./Prompt.module.scss";
...@@ -9,9 +12,6 @@ import { useContext, useEffect, useState } from "preact/hooks"; ...@@ -9,9 +12,6 @@ import { useContext, useEffect, useState } from "preact/hooks";
import { TextReact } from "../../../lib/i18n"; import { TextReact } from "../../../lib/i18n";
import { User } from "../../../mobx";
import { useData } from "../../../mobx/State";
import Message from "../../../components/common/messaging/Message"; import Message from "../../../components/common/messaging/Message";
import UserIcon from "../../../components/common/user/UserIcon"; import UserIcon from "../../../components/common/user/UserIcon";
import InputBox from "../../../components/ui/InputBox"; import InputBox from "../../../components/ui/InputBox";
...@@ -21,7 +21,7 @@ import Radio from "../../../components/ui/Radio"; ...@@ -21,7 +21,7 @@ import Radio from "../../../components/ui/Radio";
import { Children } from "../../../types/Preact"; import { Children } from "../../../types/Preact";
import { AppContext } from "../../revoltjs/RevoltClient"; import { AppContext } from "../../revoltjs/RevoltClient";
import { mapMessage, takeError } from "../../revoltjs/util"; import { takeError } from "../../revoltjs/util";
import { useIntermediate } from "../Intermediate"; import { useIntermediate } from "../Intermediate";
interface Props { interface Props {
...@@ -55,21 +55,21 @@ export function PromptModal({ ...@@ -55,21 +55,21 @@ export function PromptModal({
} }
type SpecialProps = { onClose: () => void } & ( type SpecialProps = { onClose: () => void } & (
| { type: "leave_group"; target: Channels.GroupChannel } | { type: "leave_group"; target: Channel }
| { type: "close_dm"; target: Channels.DirectMessageChannel } | { type: "close_dm"; target: Channel }
| { type: "leave_server"; target: Servers.Server } | { type: "leave_server"; target: Server }
| { type: "delete_server"; target: Servers.Server } | { type: "delete_server"; target: Server }
| { type: "delete_channel"; target: Channels.TextChannel } | { type: "delete_channel"; target: Channel }
| { type: "delete_message"; target: Channels.Message } | { type: "delete_message"; target: MessageI }
| { | {
type: "create_invite"; type: "create_invite";
target: Channels.TextChannel | Channels.GroupChannel; target: Channel;
} }
| { type: "kick_member"; target: Servers.Server; user: User } | { type: "kick_member"; target: Server; user: User }
| { type: "ban_member"; target: Servers.Server; user: User } | { type: "ban_member"; target: Server; user: User }
| { type: "unfriend_user"; target: User } | { type: "unfriend_user"; target: User }
| { type: "block_user"; target: User } | { type: "block_user"; target: User }
| { type: "create_channel"; target: Servers.Server } | { type: "create_channel"; target: Server }
); );
export const SpecialPromptModal = observer((props: SpecialProps) => { export const SpecialPromptModal = observer((props: SpecialProps) => {
...@@ -104,9 +104,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -104,9 +104,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
name = props.target.username; name = props.target.username;
break; break;
case "close_dm": case "close_dm":
name = client.users.get( name = props.target.recipient?.username;
client.channels.getRecipient(props.target._id),
)?.username;
break; break;
default: default:
name = props.target.name; name = props.target.name;
...@@ -137,27 +135,19 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -137,27 +135,19 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
try { try {
switch (props.type) { switch (props.type) {
case "unfriend_user": case "unfriend_user":
await client.users.removeFriend( await props.target.removeFriend();
props.target._id,
);
break; break;
case "block_user": case "block_user":
await client.users.blockUser( await props.target.blockUser();
props.target._id,
);
break; break;
case "leave_group": case "leave_group":
case "close_dm": case "close_dm":
case "delete_channel": case "delete_channel":
await client.channels.delete( props.target.delete();
props.target._id,
);
break; break;
case "leave_server": case "leave_server":
case "delete_server": case "delete_server":
await client.servers.delete( props.target.delete();
props.target._id,
);
break; break;
} }
...@@ -203,11 +193,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -203,11 +193,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
setProcessing(true); setProcessing(true);
try { try {
await client.channels.deleteMessage( props.target.delete();
props.target.channel,
props.target._id,
);
onClose(); onClose();
} catch (err) { } catch (err) {
setError(takeError(err)); setError(takeError(err));
...@@ -229,7 +215,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -229,7 +215,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
id={`app.special.modals.prompt.confirm_delete_message_long`} id={`app.special.modals.prompt.confirm_delete_message_long`}
/> />
<Message <Message
message={mapMessage(props.target)} message={props.target}
head={true} head={true}
contrast contrast
/> />
...@@ -247,12 +233,12 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -247,12 +233,12 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
useEffect(() => { useEffect(() => {
setProcessing(true); setProcessing(true);
client.channels props.target
.createInvite(props.target._id) .createInvite()
.then((code) => setCode(code)) .then((code) => setCode(code))
.catch((err) => setError(takeError(err))) .catch((err) => setError(takeError(err)))
.finally(() => setProcessing(false)); .finally(() => setProcessing(false));
}, []); }, [props.target]);
return ( return (
<PromptModal <PromptModal
...@@ -306,10 +292,13 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -306,10 +292,13 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
setProcessing(true); setProcessing(true);
try { try {
await client.members.kickMember( client.members
props.target._id, .getKey({
props.user._id, server: props.target._id,
); user: props.user._id,
})
?.kick();
onClose(); onClose();
} catch (err) { } catch (err) {
setError(takeError(err)); setError(takeError(err));
...@@ -357,11 +346,9 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -357,11 +346,9 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
setProcessing(true); setProcessing(true);
try { try {
await client.servers.banUser( await props.target.banUser(props.user._id, {
props.target._id, reason,
props.user._id, });
{ reason },
);
onClose(); onClose();
} catch (err) { } catch (err) {
setError(takeError(err)); setError(takeError(err));
...@@ -420,14 +407,11 @@ export const SpecialPromptModal = observer((props: SpecialProps) => { ...@@ -420,14 +407,11 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
try { try {
const channel = const channel =
await client.servers.createChannel( await props.target.createChannel({
props.target._id, type,
{ name,
type, nonce: ulid(),
name, });
nonce: ulid(),
},
);
history.push( history.push(
`/server/${props.target._id}/channel/${channel._id}`, `/server/${props.target._id}/channel/${channel._id}`,
......
import { X } from "@styled-icons/boxicons-regular"; import { X } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import styles from "./ChannelInfo.module.scss"; import styles from "./ChannelInfo.module.scss";
import Modal from "../../../components/ui/Modal"; import Modal from "../../../components/ui/Modal";
import Markdown from "../../../components/markdown/Markdown"; import Markdown from "../../../components/markdown/Markdown";
import { useChannel, useForceUpdate } from "../../revoltjs/hooks";
import { getChannelName } from "../../revoltjs/util"; import { getChannelName } from "../../revoltjs/util";
interface Props { interface Props {
channel_id: string; channel: Channel;
onClose: () => void; onClose: () => void;
} }
export function ChannelInfo({ channel_id, onClose }: Props) { export const ChannelInfo = observer(({ channel, onClose }: Props) => {
const ctx = useForceUpdate();
const channel = useChannel(channel_id, ctx);
if (!channel) return null;
if ( if (
channel.channel_type === "DirectMessage" || channel.channel_type === "DirectMessage" ||
channel.channel_type === "SavedMessages" channel.channel_type === "SavedMessages"
...@@ -30,15 +27,15 @@ export function ChannelInfo({ channel_id, onClose }: Props) { ...@@ -30,15 +27,15 @@ export function ChannelInfo({ channel_id, onClose }: Props) {
<Modal visible={true} onClose={onClose}> <Modal visible={true} onClose={onClose}>
<div className={styles.info}> <div className={styles.info}>
<div className={styles.header}> <div className={styles.header}>
<h1>{getChannelName(ctx.client, channel, true)}</h1> <h1>{getChannelName(channel, true)}</h1>
<div onClick={onClose}> <div onClick={onClose}>
<X size={36} /> <X size={36} />
</div> </div>
</div> </div>
<p> <p>
<Markdown content={channel.description} /> <Markdown content={channel.description!} />
</p> </p>
</div> </div>
</Modal> </Modal>
); );
} });
import { /* eslint-disable react-hooks/rules-of-hooks */
Attachment, import { Attachment, AttachmentMetadata } from "revolt-api/types/Autumn";
AttachmentMetadata, import { EmbedImage } from "revolt-api/types/January";
EmbedImage,
} from "revolt.js/dist/api/objects";
import styles from "./ImageViewer.module.scss"; import styles from "./ImageViewer.module.scss";
import { useContext, useEffect } from "preact/hooks";
import AttachmentActions from "../../../components/common/messaging/attachments/AttachmentActions"; import AttachmentActions from "../../../components/common/messaging/attachments/AttachmentActions";
import EmbedMediaActions from "../../../components/common/messaging/embed/EmbedMediaActions"; import EmbedMediaActions from "../../../components/common/messaging/embed/EmbedMediaActions";
......
...@@ -85,11 +85,13 @@ export function ModifyAccountModal({ onClose, field }: Props) { ...@@ -85,11 +85,13 @@ export function ModifyAccountModal({ onClose, field }: Props) {
]}> ]}>
{/* Preact / React typing incompatabilities */} {/* Preact / React typing incompatabilities */}
<form <form
onSubmit={ onSubmit={(e) => {
e.preventDefault();
handleSubmit( handleSubmit(
onSubmit, onSubmit,
) as JSX.GenericEventHandler<HTMLFormElement> // eslint-disable-next-line @typescript-eslint/no-explicit-any
}> )(e as any);
}}>
{field === "email" && ( {field === "email" && (
<FormField <FormField
type="email" type="email"
......
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { User } from "revolt.js/dist/maps/Users";
import styles from "./UserPicker.module.scss"; import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n"; import { Text } from "preact-i18n";
import { User } from "../../../mobx";
import Modal from "../../../components/ui/Modal"; import Modal from "../../../components/ui/Modal";
import { Friend } from "../../../pages/friends/Friend"; import { Friend } from "../../../pages/friends/Friend";
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
max-height: 360px; max-height: 360px;
overflow-y: scroll; overflow-y: scroll;
// ! FIXME: very temporary code
> label { > label {
> span { > span {
align-items: flex-start !important; align-items: flex-start !important;
...@@ -18,4 +17,4 @@ ...@@ -18,4 +17,4 @@
} }
} }
} }
} }
\ No newline at end of file
import { Users } from "revolt.js/dist/api/objects"; import { RelationshipStatus } from "revolt-api/types/Users";
import styles from "./UserPicker.module.scss"; import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n"; import { Text } from "preact-i18n";
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { useData } from "../../../mobx/State";
import UserCheckbox from "../../../components/common/user/UserCheckbox"; import UserCheckbox from "../../../components/common/user/UserCheckbox";
import Modal from "../../../components/ui/Modal"; import Modal from "../../../components/ui/Modal";
import { useClient } from "../../revoltjs/RevoltClient";
interface Props { interface Props {
omit?: string[]; omit?: string[];
onClose: () => void; onClose: () => void;
...@@ -19,7 +19,7 @@ export function UserPicker(props: Props) { ...@@ -19,7 +19,7 @@ export function UserPicker(props: Props) {
const [selected, setSelected] = useState<string[]>([]); const [selected, setSelected] = useState<string[]>([]);
const omit = [...(props.omit || []), "00000000000000000000000000"]; const omit = [...(props.omit || []), "00000000000000000000000000"];
const store = useData(); const client = useClient();
return ( return (
<Modal <Modal
...@@ -33,15 +33,16 @@ export function UserPicker(props: Props) { ...@@ -33,15 +33,16 @@ export function UserPicker(props: Props) {
}, },
]}> ]}>
<div className={styles.list}> <div className={styles.list}>
{[...store.users.values()] {[...client.users.values()]
.filter( .filter(
(x) => (x) =>
x && x &&
x.relationship === Users.Relationship.Friend && x.relationship === RelationshipStatus.Friend &&
!omit.includes(x._id), !omit.includes(x._id),
) )
.map((x) => ( .map((x) => (
<UserCheckbox <UserCheckbox
key={x._id}
user={x} user={x}
checked={selected.includes(x._id)} checked={selected.includes(x._id)}
onChange={(v) => { onChange={(v) => {
......
...@@ -57,13 +57,13 @@ ...@@ -57,13 +57,13 @@
gap: 8px; gap: 8px;
display: flex; display: flex;
padding: 0 1.5em; padding: 0 1.5em;
font-size: .875rem; font-size: 0.875rem;
> div { > div {
padding: 8px; padding: 8px;
cursor: pointer; cursor: pointer;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
transition: border-bottom .3s; transition: border-bottom 0.3s;
&[data-active="true"] { &[data-active="true"] {
border-bottom: 2px solid var(--foreground); border-bottom: 2px solid var(--foreground);
...@@ -81,7 +81,10 @@ ...@@ -81,7 +81,10 @@
height: 100%; height: 100%;
display: flex; display: flex;
padding: 1em 1.5em; padding: 1em 1.5em;
max-width: 560px; max-width: 560px;
max-height: 240px;
overflow-y: auto; overflow-y: auto;
flex-direction: column; flex-direction: column;
background: var(--primary-background); background: var(--primary-background);
...@@ -141,7 +144,7 @@ ...@@ -141,7 +144,7 @@
display: flex; display: flex;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
transition: background-color .1s; transition: background-color 0.1s;
color: var(--secondary-foreground); color: var(--secondary-foreground);
border-radius: var(--border-radius); border-radius: var(--border-radius);
background-color: var(--secondary-background); background-color: var(--secondary-background);
......
import { Plus, X, XCircle } from "@styled-icons/boxicons-regular"; import { Plus } from "@styled-icons/boxicons-regular";
import { Pencil } from "@styled-icons/boxicons-solid"; import { Pencil } from "@styled-icons/boxicons-solid";
import Axios, { AxiosRequestConfig } from "axios"; import Axios, { AxiosRequestConfig } from "axios";
...@@ -147,6 +147,7 @@ export function FileUploader(props: Props) { ...@@ -147,6 +147,7 @@ export function FileUploader(props: Props) {
} }
if (props.behaviour === "multi" && props.append) { if (props.behaviour === "multi" && props.append) {
// eslint-disable-next-line
useEffect(() => { useEffect(() => {
// File pasting. // File pasting.
function paste(e: ClipboardEvent) { function paste(e: ClipboardEvent) {
...@@ -210,7 +211,7 @@ export function FileUploader(props: Props) { ...@@ -210,7 +211,7 @@ export function FileUploader(props: Props) {
document.removeEventListener("dragover", dragover); document.removeEventListener("dragover", dragover);
document.removeEventListener("drop", drop); document.removeEventListener("drop", drop);
}; };
}, [props.append]); }, [openScreen, props, props.append]);
} }
if (props.style === "icon" || props.style === "banner") { if (props.style === "icon" || props.style === "banner") {
......
This diff is collapsed.
import { openDB } from "idb"; /* eslint-disable react-hooks/rules-of-hooks */
import { useHistory } from "react-router-dom";
import { Client } from "revolt.js"; import { Client } from "revolt.js";
import { Route } from "revolt.js/dist/api/routes"; import { Route } from "revolt.js/dist/api/routes";
...@@ -14,7 +13,6 @@ import { AuthState } from "../../redux/reducers/auth"; ...@@ -14,7 +13,6 @@ import { AuthState } from "../../redux/reducers/auth";
import Preloader from "../../components/ui/Preloader"; import Preloader from "../../components/ui/Preloader";
import { useData } from "../../mobx/State";
import { Children } from "../../types/Preact"; import { Children } from "../../types/Preact";
import { useIntermediate } from "../intermediate/Intermediate"; import { useIntermediate } from "../intermediate/Intermediate";
import { registerEvents, setReconnectDisallowed } from "./events"; import { registerEvents, setReconnectDisallowed } from "./events";
...@@ -36,8 +34,6 @@ export interface ClientOperations { ...@@ -36,8 +34,6 @@ export interface ClientOperations {
logout: (shouldRequest?: boolean) => Promise<void>; logout: (shouldRequest?: boolean) => Promise<void>;
loggedIn: () => boolean; loggedIn: () => boolean;
ready: () => boolean; ready: () => boolean;
openDM: (user_id: string) => Promise<string>;
} }
// By the time they are used, they should all be initialized. // By the time they are used, they should all be initialized.
...@@ -53,7 +49,6 @@ type Props = { ...@@ -53,7 +49,6 @@ type Props = {
}; };
function Context({ auth, children }: Props) { function Context({ auth, children }: Props) {
const history = useHistory();
const { openScreen } = useIntermediate(); const { openScreen } = useIntermediate();
const [status, setStatus] = useState(ClientStatus.INIT); const [status, setStatus] = useState(ClientStatus.INIT);
const [client, setClient] = useState<Client>( const [client, setClient] = useState<Client>(
...@@ -62,34 +57,10 @@ function Context({ auth, children }: Props) { ...@@ -62,34 +57,10 @@ function Context({ auth, children }: Props) {
useEffect(() => { useEffect(() => {
(async () => { (async () => {
let db;
try {
// Match sw.ts#L23
db = await openDB("state", 3, {
upgrade(db) {
for (const store of [
"channels",
"servers",
"users",
"members",
]) {
db.createObjectStore(store, {
keyPath: "_id",
});
}
},
});
} catch (err) {
console.error(
"Failed to open IndexedDB store, continuing without.",
);
}
const client = new Client({ const client = new Client({
autoReconnect: false, autoReconnect: false,
apiURL: import.meta.env.VITE_API_URL, apiURL: import.meta.env.VITE_API_URL,
debug: import.meta.env.DEV, debug: import.meta.env.DEV,
db,
}); });
setClient(client); setClient(client);
...@@ -150,26 +121,16 @@ function Context({ auth, children }: Props) { ...@@ -150,26 +121,16 @@ function Context({ auth, children }: Props) {
loggedIn: () => typeof auth.active !== "undefined", loggedIn: () => typeof auth.active !== "undefined",
ready: () => ready: () =>
operations.loggedIn() && typeof client.user !== "undefined", operations.loggedIn() && typeof client.user !== "undefined",
openDM: async (user_id: string) => {
const channel = await client.users.openDM(user_id);
history.push(`/channel/${channel!._id}`);
return channel!._id;
},
}; };
}, [client, auth.active]); }, [client, auth.active, openScreen]);
const store = useData();
useEffect( useEffect(
() => registerEvents({ operations }, setStatus, client, store), () => registerEvents({ operations }, setStatus, client),
[client, store], [client, operations],
); );
useEffect(() => { useEffect(() => {
(async () => { (async () => {
if (client.db) {
await client.restore();
}
if (auth.active) { if (auth.active) {
dispatch({ type: "QUEUE_FAIL_ALL" }); dispatch({ type: "QUEUE_FAIL_ALL" });
...@@ -218,6 +179,7 @@ function Context({ auth, children }: Props) { ...@@ -218,6 +179,7 @@ function Context({ auth, children }: Props) {
setStatus(ClientStatus.READY); setStatus(ClientStatus.READY);
} }
})(); })();
// eslint-disable-next-line
}, []); }, []);
if (status === ClientStatus.LOADING) { if (status === ClientStatus.LOADING) {
......
/** /**
* This file monitors the message cache to delete any queued messages that have already sent. * This file monitors the message cache to delete any queued messages that have already sent.
*/ */
import { Message } from "revolt.js"; import { Message } from "revolt.js/dist/maps/Messages";
import { useContext, useEffect } from "preact/hooks"; import { useContext, useEffect } from "preact/hooks";
import { dispatch } from "../../redux"; import { dispatch } from "../../redux";
import { connectState } from "../../redux/connector"; import { connectState } from "../../redux/connector";
import { QueuedMessage } from "../../redux/reducers/queue"; import { QueuedMessage } from "../../redux/reducers/queue";
import { Typing } from "../../redux/reducers/typing";
import { AppContext } from "./RevoltClient"; import { AppContext } from "./RevoltClient";
type Props = { type Props = {
messages: QueuedMessage[]; messages: QueuedMessage[];
typing: Typing;
}; };
function StateMonitor(props: Props) { function StateMonitor(props: Props) {
...@@ -39,31 +37,7 @@ function StateMonitor(props: Props) { ...@@ -39,31 +37,7 @@ function StateMonitor(props: Props) {
client.addListener("message", add); client.addListener("message", add);
return () => client.removeListener("message", add); return () => client.removeListener("message", add);
}, [props.messages]); }, [client, props.messages]);
useEffect(() => {
function removeOld() {
if (!props.typing) return;
for (const channel of Object.keys(props.typing)) {
const users = props.typing[channel];
for (const user of users) {
if (+new Date() > user.started + 5000) {
dispatch({
type: "TYPING_STOP",
channel,
user: user.id,
});
}
}
}
}
removeOld();
const interval = setInterval(removeOld, 1000);
return () => clearInterval(interval);
}, [props.typing]);
return null; return null;
} }
...@@ -71,6 +45,5 @@ function StateMonitor(props: Props) { ...@@ -71,6 +45,5 @@ function StateMonitor(props: Props) {
export default connectState(StateMonitor, (state) => { export default connectState(StateMonitor, (state) => {
return { return {
messages: [...state.queue], messages: [...state.queue],
typing: state.typing,
}; };
}); });
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* This file monitors changes to settings and syncs them to the server. * This file monitors changes to settings and syncs them to the server.
*/ */
import isEqual from "lodash.isequal"; import isEqual from "lodash.isequal";
import { Sync } from "revolt.js/dist/api/objects"; import { UserSettings } from "revolt-api/types/Sync";
import { ClientboundNotification } from "revolt.js/dist/websocket/notifications"; import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
import { useContext, useEffect } from "preact/hooks"; import { useCallback, useContext, useEffect, useMemo } from "preact/hooks";
import { dispatch } from "../../redux"; import { dispatch } from "../../redux";
import { connectState } from "../../redux/connector"; import { connectState } from "../../redux/connector";
...@@ -28,10 +28,10 @@ type Props = { ...@@ -28,10 +28,10 @@ type Props = {
notifications: Notifications; notifications: Notifications;
}; };
const lastValues: { [key in SyncKeys]?: any } = {}; const lastValues: { [key in SyncKeys]?: unknown } = {};
export function mapSync( export function mapSync(
packet: Sync.UserSettings, packet: UserSettings,
revision?: Record<string, number>, revision?: Record<string, number>,
) { ) {
const update: { [key in SyncKeys]?: [number, SyncData[key]] } = {}; const update: { [key in SyncKeys]?: [number, SyncData[key]] } = {};
...@@ -78,31 +78,38 @@ function SyncManager(props: Props) { ...@@ -78,31 +78,38 @@ function SyncManager(props: Props) {
.syncFetchUnreads() .syncFetchUnreads()
.then((unreads) => dispatch({ type: "UNREADS_SET", unreads })); .then((unreads) => dispatch({ type: "UNREADS_SET", unreads }));
} }
}, [status]); }, [client, props.sync?.disabled, status]);
function syncChange(key: SyncKeys, data: any) { const syncChange = useCallback(
const timestamp = +new Date(); (key: SyncKeys, data: unknown) => {
dispatch({ const timestamp = +new Date();
type: "SYNC_SET_REVISION", dispatch({
key, type: "SYNC_SET_REVISION",
timestamp, key,
}); timestamp,
});
client.syncSetSettings(
{ client.syncSetSettings(
[key]: data, {
}, [key]: data as string,
timestamp, },
); timestamp,
} );
},
const disabled = props.sync.disabled ?? []; [client],
);
const disabled = useMemo(
() => props.sync.disabled ?? [],
[props.sync.disabled],
);
for (const [key, object] of [ for (const [key, object] of [
["appearance", props.settings.appearance], ["appearance", props.settings.appearance],
["theme", props.settings.theme], ["theme", props.settings.theme],
["locale", props.locale], ["locale", props.locale],
["notifications", props.notifications], ["notifications", props.notifications],
] as [SyncKeys, any][]) { ] as [SyncKeys, unknown][]) {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => { useEffect(() => {
if (disabled.indexOf(key) === -1) { if (disabled.indexOf(key) === -1) {
if (typeof lastValues[key] !== "undefined") { if (typeof lastValues[key] !== "undefined") {
...@@ -113,7 +120,7 @@ function SyncManager(props: Props) { ...@@ -113,7 +120,7 @@ function SyncManager(props: Props) {
} }
lastValues[key] = object; lastValues[key] = object;
}, [disabled, object]); }, [key, syncChange, disabled, object]);
} }
useEffect(() => { useEffect(() => {
...@@ -131,7 +138,7 @@ function SyncManager(props: Props) { ...@@ -131,7 +138,7 @@ function SyncManager(props: Props) {
client.addListener("packet", onPacket); client.addListener("packet", onPacket);
return () => client.removeListener("packet", onPacket); return () => client.removeListener("packet", onPacket);
}, [disabled, props.sync]); }, [client, disabled, props.sync]);
return null; return null;
} }
......
This diff is collapsed.
This diff is collapsed.
import { Client } from "revolt.js"; import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel, Message, User } from "revolt.js/dist/api/objects";
import { Text } from "preact-i18n"; import { Text } from "preact-i18n";
import { Children } from "../../types/Preact"; import { Children } from "../../types/Preact";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function takeError(error: any): string { export function takeError(error: any): string {
const type = error?.response?.data?.type; const type = error?.response?.data?.type;
const id = type; const id = type;
...@@ -23,7 +23,6 @@ export function takeError(error: any): string { ...@@ -23,7 +23,6 @@ export function takeError(error: any): string {
} }
export function getChannelName( export function getChannelName(
client: Client,
channel: Channel, channel: Channel,
prefixType?: boolean, prefixType?: boolean,
): Children { ): Children {
...@@ -31,11 +30,10 @@ export function getChannelName( ...@@ -31,11 +30,10 @@ export function getChannelName(
return <Text id="app.navigation.tabs.saved" />; return <Text id="app.navigation.tabs.saved" />;
if (channel.channel_type === "DirectMessage") { if (channel.channel_type === "DirectMessage") {
const uid = client.channels.getRecipient(channel._id);
return ( return (
<> <>
{prefixType && "@"} {prefixType && "@"}
{client.users.get(uid)?.username} {channel.recipient!.username}
</> </>
); );
} }
...@@ -46,12 +44,3 @@ export function getChannelName( ...@@ -46,12 +44,3 @@ export function getChannelName(
return <>{channel.name}</>; return <>{channel.name}</>;
} }
export type MessageObject = Omit<Message, "edited"> & { edited?: string };
export function mapMessage(message: Partial<Message>) {
const { edited, ...msg } = message;
return {
...msg,
edited: edited?.$date,
} as MessageObject;
}
This diff is collapsed.
This diff is collapsed.
/* eslint-disable react-hooks/rules-of-hooks */
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
const counts: { [key: string]: number } = {}; const counts: { [key: string]: number } = {};
......