chore(refactor): delete context/revoltjs folder

This commit is contained in:
Paul Makles
2022-07-06 13:08:03 +01:00
parent e37140dcd0
commit c51b024329
30 changed files with 77 additions and 161 deletions

View File

@@ -0,0 +1,34 @@
// ! This should be moved into @revoltchat/ui
import { Channel } from "revolt.js";
import { Text } from "preact-i18n";
interface Props {
channel?: Channel;
prefix?: boolean;
}
/**
* Channel display name
*/
export function ChannelName({ channel, prefix }: Props) {
if (!channel) return <></>;
if (channel.channel_type === "SavedMessages")
return <Text id="app.navigation.tabs.saved" />;
if (channel.channel_type === "DirectMessage") {
return (
<>
{prefix && "@"}
{channel.recipient!.username}
</>
);
}
if (channel.channel_type === "TextChannel" && prefix) {
return <>{`#${channel.name}`}</>;
}
return <>{channel.name}</>;
}

View File

@@ -0,0 +1,41 @@
import { observer } from "mobx-react-lite";
import { Redirect } from "react-router-dom";
import { Preloader } from "@revoltchat/ui";
import { clientController } from "../ClientController";
interface Props {
auth?: boolean;
blockRender?: boolean;
children: Children;
}
/**
* Check that we are logged in or out and redirect accordingly.
* Also prevent render until the client is ready to display.
*/
export const CheckAuth = observer((props: Props) => {
const loggedIn = clientController.isLoggedIn();
// Redirect if logged out on authenticated page or vice-versa.
if (props.auth && !loggedIn) {
if (props.blockRender) return null;
return <Redirect to="/login" />;
} else if (!props.auth && loggedIn) {
if (props.blockRender) return null;
return <Redirect to="/" />;
}
// Block render if client is getting ready to work.
if (
props.auth &&
clientController.isLoggedIn() &&
!clientController.isReady()
) {
return <Preloader type="spinner" />;
}
return <>{props.children}</>;
});

View File

@@ -0,0 +1,29 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function takeError(error: any): string {
if (error.response) {
const type = error.response.data?.type;
if (type) {
return type;
}
switch (error.response.status) {
case 429:
return "TooManyRequests";
case 401:
case 403:
return "Unauthorized";
default:
return "UnknownError";
}
} else if (error.request) {
return "NetworkError";
}
console.error(error);
return "UnknownError";
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function mapError(error: any): never {
throw takeError(error);
}

View File

@@ -0,0 +1,87 @@
.uploader {
display: flex;
flex-direction: column;
&.icon {
.image {
border-radius: var(--border-radius-half);
}
}
&.banner {
.image {
border-radius: var(--border-radius);
}
.modify {
gap: 4px;
flex-direction: row;
}
}
.image {
cursor: pointer;
overflow: hidden;
background-size: cover;
background-position: center;
background-color: var(--secondary-background);
.uploading {
width: 100%;
height: 100%;
display: grid;
place-items: center;
background: rgba(0, 0, 0, 0.5);
}
&:hover .edit {
opacity: 1;
}
&:active .edit {
filter: brightness(0.8);
}
&.desaturate {
filter: brightness(0.7) sepia(50%) grayscale(90%);
}
.edit {
opacity: 0;
width: 100%;
height: 100%;
display: grid;
color: white;
place-items: center;
background: rgba(95, 95, 95, 0.5);
transition: 0.2s ease-in-out opacity;
}
}
.modify {
display: flex;
margin-top: 5px;
font-size: 12px;
align-items: center;
flex-direction: column;
justify-content: center;
:first-child {
cursor: pointer;
}
.small {
display: flex;
font-size: 10px;
flex-direction: column;
color: var(--tertiary-foreground);
}
}
&[data-uploading="true"] {
.image,
.modify:first-child {
cursor: not-allowed !important;
}
}
}

View File

@@ -0,0 +1,324 @@
import { Plus } from "@styled-icons/boxicons-regular";
import { Pencil } from "@styled-icons/boxicons-solid";
import Axios, { AxiosRequestConfig } from "axios";
import styles from "./FileUploads.module.scss";
import classNames from "classnames";
import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import { IconButton, Preloader } from "@revoltchat/ui";
import { determineFileSize } from "../../../../lib/fileSize";
import { modalController } from "../../../modals/ModalController";
import { useClient } from "../../ClientController";
import { takeError } from "../error";
type BehaviourType =
| { behaviour: "ask"; onChange: (file: File) => void }
| { behaviour: "upload"; onUpload: (id: string) => Promise<void> }
| {
behaviour: "multi";
onChange: (files: File[]) => void;
append?: (files: File[]) => void;
};
type StyleType =
| {
style: "icon" | "banner";
width?: number;
height?: number;
previewURL?: string;
defaultPreview?: string;
desaturateDefault?: boolean;
}
| {
style: "attachment";
attached: boolean;
uploading: boolean;
cancel: () => void;
size?: number;
};
type Props = BehaviourType &
StyleType & {
fileType:
| "backgrounds"
| "icons"
| "avatars"
| "attachments"
| "banners";
maxFileSize: number;
remove: () => Promise<void>;
};
export async function uploadFile(
autumnURL: string,
tag: string,
file: File,
config?: AxiosRequestConfig,
) {
const formData = new FormData();
formData.append("file", file);
const res = await Axios.post(`${autumnURL}/${tag}`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
...config,
});
return res.data.id;
}
let input: HTMLInputElement;
export function grabFiles(
maxFileSize: number,
cb: (files: File[]) => void,
tooLarge: () => void,
multiple?: boolean,
) {
if (input) {
input.remove();
}
input = document.createElement("input");
input.accept = "*";
input.type = "file";
input.multiple = multiple ?? false;
input.style.display = "none";
input.addEventListener("change", async (e) => {
const files = (e.currentTarget as HTMLInputElement)?.files;
if (!files) return;
for (const file of files) {
if (file.size > maxFileSize) {
return tooLarge();
}
}
cb(Array.from(files));
});
// iOS requires us to append the file input
// to DOM to allow us to add any images
document.body.appendChild(input);
input.click();
}
export function FileUploader(props: Props) {
const { fileType, maxFileSize, remove } = props;
const client = useClient();
const [uploading, setUploading] = useState(false);
function onClick() {
if (uploading) return;
grabFiles(
maxFileSize,
async (files) => {
setUploading(true);
try {
if (props.behaviour === "multi") {
props.onChange(files);
} else if (props.behaviour === "ask") {
props.onChange(files[0]);
} else {
await props.onUpload(
await uploadFile(
client.configuration!.features.autumn.url,
fileType,
files[0],
),
);
}
} catch (err) {
return modalController.push({
type: "error",
error: takeError(err),
});
} finally {
setUploading(false);
}
},
() =>
modalController.push({
type: "error",
error: "FileTooLarge",
}),
props.behaviour === "multi",
);
}
function removeOrUpload() {
if (uploading) return;
if (props.style === "attachment") {
if (props.attached) {
props.remove();
} else {
onClick();
}
} else if (props.previewURL) {
props.remove();
} else {
onClick();
}
}
if (props.behaviour === "multi" && props.append) {
// eslint-disable-next-line
useEffect(() => {
// File pasting.
function paste(e: ClipboardEvent) {
const items = e.clipboardData?.items;
if (typeof items === "undefined") return;
if (props.behaviour !== "multi" || !props.append) return;
const files = [];
for (const item of items) {
if (!item.type.startsWith("text/")) {
const blob = item.getAsFile();
if (blob) {
if (blob.size > props.maxFileSize) {
modalController.push({
type: "error",
error: "FileTooLarge",
});
continue;
}
files.push(blob);
}
}
}
props.append(files);
}
// Let the browser know we can drop files.
function dragover(e: DragEvent) {
e.stopPropagation();
e.preventDefault();
if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
}
// File dropping.
function drop(e: DragEvent) {
e.preventDefault();
if (props.behaviour !== "multi" || !props.append) return;
const dropped = e.dataTransfer?.files;
if (dropped) {
const files = [];
for (const item of dropped) {
if (item.size > props.maxFileSize) {
modalController.push({
type: "error",
error: "FileTooLarge",
});
continue;
}
files.push(item);
}
props.append(files);
}
}
document.addEventListener("paste", paste);
document.addEventListener("dragover", dragover);
document.addEventListener("drop", drop);
return () => {
document.removeEventListener("paste", paste);
document.removeEventListener("dragover", dragover);
document.removeEventListener("drop", drop);
};
}, [props, props.append]);
}
if (props.style === "icon" || props.style === "banner") {
const { style, previewURL, defaultPreview, width, height } = props;
return (
<div
className={classNames(styles.uploader, {
[styles.icon]: style === "icon",
[styles.banner]: style === "banner",
})}
style={{
alignItems: props.style === "icon" ? "center" : "none",
}}
data-uploading={uploading}>
<div
className={classNames(
styles.image,
props.desaturateDefault &&
previewURL == null &&
styles.desaturate,
)}
style={{
backgroundImage:
style === "icon"
? `url('${previewURL ?? defaultPreview}')`
: previewURL
? `linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) ), url('${previewURL}')`
: "none",
width,
height,
}}
onClick={onClick}>
{uploading ? (
<div className={styles.uploading}>
<Preloader type="ring" />
</div>
) : (
<div className={styles.edit}>
<Pencil size={30} />
</div>
)}
</div>
<div className={styles.modify}>
<span onClick={removeOrUpload}>
{uploading ? (
<Text id="app.main.channel.uploading_file" />
) : props.previewURL ? (
<Text id="app.settings.actions.remove" />
) : (
<Text id="app.settings.actions.upload" />
)}
</span>
<span className={styles.small}>
<Text
id="app.settings.actions.max_filesize"
fields={{
filesize: determineFileSize(maxFileSize),
}}
/>
</span>
</div>
</div>
);
} else if (props.style === "attachment") {
const { attached, uploading, cancel, size } = props;
return (
<IconButton
onClick={() => {
if (uploading) return cancel();
if (attached) return remove();
onClick();
}}
rotate={uploading || attached ? "45deg" : undefined}>
<Plus size={size} />
</IconButton>
);
}
return null;
}

View File

@@ -4,9 +4,8 @@ import { Text } from "preact-i18n";
import { ModalForm } from "@revoltchat/ui";
import { mapError } from "../../../context/revoltjs/util";
import { useClient } from "../../client/ClientController";
import { mapError } from "../../client/jsx/error";
import { ModalProps } from "../types";
/**

View File

@@ -7,8 +7,7 @@ import { ModalForm } from "@revoltchat/ui";
import { noopAsync } from "../../../lib/js";
import { takeError } from "../../../context/revoltjs/util";
import { takeError } from "../../client/jsx/error";
import { modalController } from "../ModalController";
import { ModalProps } from "../types";

View File

@@ -4,9 +4,8 @@ import { Text } from "preact-i18n";
import { ModalForm } from "@revoltchat/ui";
import { mapError } from "../../../context/revoltjs/util";
import { useClient } from "../../client/ClientController";
import { mapError } from "../../client/jsx/error";
import { ModalProps } from "../types";
/**

View File

@@ -7,10 +7,9 @@ import { Category, Error, Modal } from "@revoltchat/ui";
import { noopTrue } from "../../../lib/js";
import { takeError } from "../../../context/revoltjs/util";
import FormField from "../../../pages/login/FormField";
import { useClient } from "../../client/ClientController";
import { takeError } from "../../client/jsx/error";
import { ModalProps } from "../types";
interface FormInputs {

View File

@@ -19,8 +19,7 @@ import {
import { noop } from "../../../lib/js";
import { FileUploader } from "../../../context/revoltjs/FileUploads";
import { FileUploader } from "../../client/jsx/legacy/FileUploads";
import { ModalProps } from "../types";
const Preview = styled(Centred)`

View File

@@ -9,10 +9,10 @@ import { Category, Modal } from "@revoltchat/ui";
import { noopTrue } from "../../../../lib/js";
import { I18nError } from "../../../../context/Locale";
import { takeError } from "../../../../context/revoltjs/util";
import FormField from "../../../../pages/login/FormField";
import { useClient } from "../../../client/ClientController";
import { takeError } from "../../../client/jsx/error";
import { modalController } from "../../ModalController";
import { ModalProps } from "../../types";

View File

@@ -6,11 +6,10 @@ import { useState } from "preact/hooks";
import { Button, Preloader } from "@revoltchat/ui";
import { takeError } from "../../../../context/revoltjs/util";
import wideSVG from "/assets/wide.svg";
import FormField from "../../../../pages/login/FormField";
import { takeError } from "../../../client/jsx/error";
import { ModalProps } from "../../types";
interface FormInputs {