diff --git a/src/components/common/ServerHeader.tsx b/src/components/common/ServerHeader.tsx new file mode 100644 index 00000000..e2a89df8 --- /dev/null +++ b/src/components/common/ServerHeader.tsx @@ -0,0 +1,39 @@ +import Header from "../ui/Header"; +import styled from "styled-components"; +import { Link } from "react-router-dom"; +import IconButton from "../ui/IconButton"; +import { Settings } from "@styled-icons/feather"; +import { Server } from "revolt.js/dist/api/objects"; +import { ServerPermission } from "revolt.js/dist/api/permissions"; +import { HookContext, useServerPermission } from "../../context/revoltjs/hooks"; + +interface Props { + server: Server, + ctx: HookContext +} + +const ServerName = styled.div` + flex-grow: 1; +`; + +export default function ServerHeader({ server, ctx }: Props) { + const permissions = useServerPermission(server._id, ctx); + const bannerURL = ctx.client.servers.getBannerURL(server._id, { width: 480 }, true); + + return ( +
+ + { server.name } + + { (permissions & ServerPermission.ManageServer) > 0 &&
+ + + + + +
} +
+ ) +} diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx index f4cae5fd..b84bb69c 100644 --- a/src/components/navigation/left/ServerSidebar.tsx +++ b/src/components/navigation/left/ServerSidebar.tsx @@ -14,6 +14,7 @@ import { connectState } from "../../../redux/connector"; import PaintCounter from "../../../lib/PaintCounter"; import styled from "styled-components"; import { attachContextMenu } from 'preact-context-menu'; +import ServerHeader from "../../common/ServerHeader"; interface Props { unreads: Unreads; @@ -45,7 +46,6 @@ function ServerSidebar(props: Props & WithDispatcher) { const server = useServer(server_id, ctx); if (!server) return ; - const permissions = useServerPermission(server._id, ctx); const channels = (useChannels(server.channels, ctx) .filter(entry => typeof entry !== 'undefined') as Readonly[]) .map(x => mapChannelWithUnread(x, props.unreads)); @@ -55,16 +55,7 @@ function ServerSidebar(props: Props & WithDispatcher) { return ( -
-
- { server.name } -
- { (permissions & ServerPermission.ManageServer) > 0 &&
- {/**/} - - {/**/} -
} -
+ {channels.map(entry => { diff --git a/src/pages/Open.tsx b/src/pages/Open.tsx new file mode 100644 index 00000000..7ee8120c --- /dev/null +++ b/src/pages/Open.tsx @@ -0,0 +1,72 @@ +import { Text } from "preact-i18n"; +import Header from "../components/ui/Header"; +import { useContext, useEffect } from "preact/hooks"; +import { useHistory, useParams } from "react-router-dom"; +import { useIntermediate } from "../context/intermediate/Intermediate"; +import { useChannels, useForceUpdate, useUser } from "../context/revoltjs/hooks"; +import { AppContext, ClientStatus, StatusContext } from "../context/revoltjs/RevoltClient"; + +export default function Open() { + const history = useHistory(); + const client = useContext(AppContext); + const status = useContext(StatusContext); + const { id } = useParams<{ id: string }>(); + const { openScreen } = useIntermediate(); + + if (status !== ClientStatus.ONLINE) { + return ( +
+ +
+ ); + } + + const ctx = useForceUpdate(); + const channels = useChannels(undefined, ctx); + const user = useUser(id, ctx); + + useEffect(() => { + if (id === "saved") { + for (const channel of channels) { + if (channel?.channel_type === "SavedMessages") { + history.push(`/channel/${channel._id}`); + return; + } + } + + client.users + .openDM(client.user?._id as string) + .then(channel => history.push(`/channel/${channel?._id}`)) + .catch(error => openScreen({ id: "error", error })); + + return; + } + + if (user) { + const channel: string | undefined = channels.find( + channel => + channel?.channel_type === "DirectMessage" && + channel.recipients.includes(id) + )?._id; + + if (channel) { + history.push(`/channel/${channel}`); + } else { + client.users + .openDM(id) + .then(channel => history.push(`/channel/${channel?._id}`)) + .catch(error => openScreen({ id: "error", error })); + } + + return; + } + + history.push("/"); + }, []); + + return ( +
+ +
+ ); +} diff --git a/src/pages/RevoltApp.tsx b/src/pages/RevoltApp.tsx index f20c2031..53400ce8 100644 --- a/src/pages/RevoltApp.tsx +++ b/src/pages/RevoltApp.tsx @@ -13,7 +13,9 @@ import LeftSidebar from "../components/navigation/LeftSidebar"; import RightSidebar from "../components/navigation/RightSidebar"; import BottomNavigation from "../components/navigation/BottomNavigation"; +import Open from "./Open"; import Home from './home/Home'; +import Invite from "./invite/Invite"; import Friends from "./friends/Friends"; import Channel from "./channels/Channel"; import Settings from './settings/Settings'; @@ -64,6 +66,8 @@ export default function App() { + + @@ -75,15 +79,3 @@ export default function App() { ); }; - -/** - * - * - - - - - {/* - - - */ diff --git a/src/pages/invite/Invite.module.scss b/src/pages/invite/Invite.module.scss new file mode 100644 index 00000000..58814516 --- /dev/null +++ b/src/pages/invite/Invite.module.scss @@ -0,0 +1,75 @@ +.invite { + height: 100%; + display: flex; + color: white; + user-select: none; + align-items: center; + flex-direction: column; + background-size: cover; + justify-content: center; + background-position: center; + + * { + overflow: visible; + } + + .icon { + width: 64px; + z-index: 100; + text-align: left; + position: relative; + + > * { + top: -32px; + position: absolute; + } + } + + .leave { + top: 8px; + left: 8px; + cursor: pointer; + position: fixed; + } + + .details { + text-align: center; + border-radius: 3px; + align-self: center; + padding: 32px 16px 16px 16px; + background: rgba(0, 0, 0, 0.6); + + h1 { + margin: 0; + font-weight: 500; + } + + h2 { + margin: 4px; + opacity: 0.7; + font-size: 0.8em; + font-weight: 400; + } + + h3 { + gap: 8px; + display: flex; + font-size: 1em; + font-weight: 400; + flex-direction: row; + justify-content: center; + } + + button { + margin: auto; + display: block; + background: rgba(0, 0, 0, 0.8); + } + } +} + +.preloader { + height: 100%; + display: grid; + place-items: center; +} diff --git a/src/pages/invite/Invite.tsx b/src/pages/invite/Invite.tsx new file mode 100644 index 00000000..cb01eaf1 --- /dev/null +++ b/src/pages/invite/Invite.tsx @@ -0,0 +1,87 @@ +import styles from './Invite.module.scss'; +import Button from '../../components/ui/Button'; +import { ArrowLeft } from "@styled-icons/feather"; +import Overline from '../../components/ui/Overline'; +import { Invites } from "revolt.js/dist/api/objects"; +import Preloader from '../../components/ui/Preloader'; +import { takeError } from "../../context/revoltjs/util"; +import { useHistory, useParams } from "react-router-dom"; +import ServerIcon from '../../components/common/ServerIcon'; +import UserIcon from '../../components/common/user/UserIcon'; +import { useContext, useEffect, useState } from "preact/hooks"; +import RequiresOnline from '../../context/revoltjs/RequiresOnline'; +import { AppContext, ClientStatus, StatusContext } from "../../context/revoltjs/RevoltClient"; + +export default function Invite() { + const history = useHistory(); + const client = useContext(AppContext); + const status = useContext(StatusContext); + const { code } = useParams<{ code: string }>(); + const [ processing, setProcessing ] = useState(false); + const [ error, setError ] = useState(undefined); + const [ invite, setInvite ] = useState(undefined); + + useEffect(() => { + if (typeof invite === 'undefined' && (status === ClientStatus.ONLINE || status === ClientStatus.READY)) { + client.fetchInvite(code) + .then(data => setInvite(data)) + .catch(err => setError(takeError(err))) + } + }, [ status ]); + + if (typeof invite === 'undefined') { + return ( +
+ + { error ? + : } + +
+ ) + } + + return ( +
+
+ history.push('/')} /> +
+ + { !processing && +
+ +
} + +
+ { processing ? : + <> +

{ invite.server_name }

+

#{invite.channel_name}

+

Invited by { invite.user_name }

+ + + + } +
+
+ ); +}