diff --git a/src/components/ui/IconButton.tsx b/src/components/ui/IconButton.tsx index a0c757840a45501f5f1d410bf182e6e10905984c..bf946abc275773592ce1654ad7e4876f3adaae8a 100644 --- a/src/components/ui/IconButton.tsx +++ b/src/components/ui/IconButton.tsx @@ -12,6 +12,7 @@ export default styled.div<Props>` display: grid; cursor: pointer; place-items: center; + transition: .1s ease background-color; fill: ${normal}; color: ${normal}; diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx index 5ca77857acb372ee7f2cc71607d311f02e6c649a..086178274f11178f1d9a5855b5587095adbd0e40 100644 --- a/src/context/revoltjs/RevoltClient.tsx +++ b/src/context/revoltjs/RevoltClient.tsx @@ -3,12 +3,12 @@ import { Client } from "revolt.js"; import { takeError } from "./util"; import { createContext } from "preact"; import { Children } from "../../types/Preact"; +import { useHistory } from 'react-router-dom'; import { Route } from "revolt.js/dist/api/routes"; import { connectState } from "../../redux/connector"; import Preloader from "../../components/ui/Preloader"; import { WithDispatcher } from "../../redux/reducers"; import { AuthState } from "../../redux/reducers/auth"; -import { SyncOptions } from "../../redux/reducers/sync"; import { useEffect, useMemo, useState } from "preact/hooks"; import { useIntermediate } from '../intermediate/Intermediate'; import { registerEvents, setReconnectDisallowed } from "./events"; @@ -30,6 +30,8 @@ export interface ClientOperations { logout: (shouldRequest?: boolean) => Promise<void>; loggedIn: () => boolean; ready: () => boolean; + + openDM: (user_id: string) => Promise<string>; } export const AppContext = createContext<Client>(undefined as any); @@ -42,6 +44,7 @@ type Props = WithDispatcher & { }; function Context({ auth, children, dispatcher }: Props) { + const history = useHistory(); const { openScreen } = useIntermediate(); const [status, setStatus] = useState(ClientStatus.INIT); const [client, setClient] = useState<Client>(undefined as unknown as Client); @@ -132,7 +135,12 @@ function Context({ auth, children, dispatcher }: Props) { ready: () => ( operations.loggedIn() && typeof client.user !== "undefined" - ) + ), + openDM: async (user_id: string) => { + let channel = await client.users.openDM(user_id); + history.push(`/channel/${channel!._id}`); + return channel!._id; + } } }, [ client, auth.active ]); diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index ab28639b016a3cd4d0fc062dcb3fe046501da666..a8183e511c3de3768464c8e600fcebdcf28a2c8a 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -72,16 +72,16 @@ display: flex; gap: 12px; - > a { - height: 40px; + .button { width: 40px; + height: 40px; - &:nth-child(1):hover { - background: var(--status-online); //TOFIX: change to normal green color + &:hover.error { + background: var(--error); } - &:nth-child(3):hover { - background: var(--error); + &:hover.success { + background: var(--success); } } } diff --git a/src/pages/friends/Friend.tsx b/src/pages/friends/Friend.tsx index dd51b263f527e7a313e0d73e13f902cc045d923b..2befba18a5277019fd07229e95e6406f31ffbb61 100644 --- a/src/pages/friends/Friend.tsx +++ b/src/pages/friends/Friend.tsx @@ -1,18 +1,19 @@ import { Text } from "preact-i18n"; -import { Link } from "react-router-dom"; +import classNames from "classnames"; import styles from "./Friend.module.scss"; import { useContext } from "preact/hooks"; import { Children } from "../../types/Preact"; -import { X, Plus } from "@styled-icons/boxicons-regular"; -import { PhoneCall, Envelope } from "@styled-icons/boxicons-solid"; import IconButton from "../../components/ui/IconButton"; import { attachContextMenu } from "preact-context-menu"; +import { X, Plus } from "@styled-icons/boxicons-regular"; import { User, Users } from "revolt.js/dist/api/objects"; import { stopPropagation } from "../../lib/stopPropagation"; +import { VoiceOperationsContext } from "../../context/Voice"; import UserIcon from "../../components/common/user/UserIcon"; import UserStatus from '../../components/common/user/UserStatus'; -import { AppContext } from "../../context/revoltjs/RevoltClient"; +import { PhoneCall, Envelope } from "@styled-icons/boxicons-solid"; import { useIntermediate } from "../../context/intermediate/Intermediate"; +import { AppContext, OperationsContext } from "../../context/revoltjs/RevoltClient"; interface Props { user: User; @@ -21,6 +22,8 @@ interface Props { export function Friend({ user }: Props) { const client = useContext(AppContext); const { openScreen } = useIntermediate(); + const { openDM } = useContext(OperationsContext); + const { connect } = useContext(VoiceOperationsContext); const actions: Children[] = []; let subtext: Children = null; @@ -29,18 +32,16 @@ export function Friend({ user }: Props) { subtext = <UserStatus user={user} /> actions.push( <> - <Link to={'/open/' + user._id}> <IconButton type="circle" - onClick={stopPropagation}> + className={classNames(styles.button, styles.success)} + onClick={ev => stopPropagation(ev, openDM(user._id).then(connect))}> <PhoneCall size={20} /> </IconButton> - </Link> - <Link to={'/open/' + user._id}> <IconButton type="circle" - onClick={stopPropagation}> + className={styles.button} + onClick={ev => stopPropagation(ev, openDM(user._id))}> <Envelope size={20} /> </IconButton> - </Link> </> ); } @@ -48,6 +49,7 @@ export function Friend({ user }: Props) { if (user.relationship === Users.Relationship.Incoming) { actions.push( <IconButton type="circle" + className={styles.button} onClick={ev => stopPropagation(ev, client.users.addFriend(user.username))}> <Plus size={24} /> </IconButton> @@ -67,6 +69,7 @@ export function Friend({ user }: Props) { ) { actions.push( <IconButton type="circle" + className={classNames(styles.button, styles.error)} onClick={ev => stopPropagation(ev, client.users.removeFriend(user._id))}> <X size={24} /> </IconButton> @@ -76,6 +79,7 @@ export function Friend({ user }: Props) { if (user.relationship === Users.Relationship.Blocked) { actions.push( <IconButton type="circle" + className={classNames(styles.button, styles.error)} onClick={ev => stopPropagation(ev, client.users.unblockUser(user._id))}> <X size={24} /> </IconButton> diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 343a9fc07d68a65d1dfa05ccc1ea9a999a152e0f..b144030b86d39c92340e0a5ab463818b2a7d0e61 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -29,6 +29,9 @@ export default function Friends() { x => x.relationship === Users.Relationship.Blocked ); + const online = friends.filter(x => x.online && x.status?.presence !== Users.Presence.Invisible); + const offline = friends.filter(x => !x.online || x.status?.presence === Users.Presence.Invisible); + return ( <> <Header placement="primary"> @@ -36,7 +39,7 @@ export default function Friends() { <div className={styles.title}> <Text id="app.navigation.tabs.friends" /> </div> - <IconButton onClick={() => openScreen({ id: 'special_input', type: 'add_friend' })}> {/* TOFIX: Make sure this opens the "Start Group DM" window on click */} + <IconButton onClick={() => openScreen({ id: 'special_input', type: 'create_group' })}> <Conversation size={24} /> </IconButton> <IconButton onClick={() => openScreen({ id: 'special_input', type: 'add_friend' })}> @@ -64,13 +67,22 @@ export default function Friends() { {pending.map(y => ( <Friend key={y._id} user={y} /> ))} - {friends.length > 0 && ( + {online.length > 0 && ( + <Overline className={styles.overline} type="subtle"> + <Text id="app.status.online" /> —{" "} + {online.length} + </Overline> + )} + {online.map(y => ( + <Friend key={y._id} user={y} /> + ))} + {offline.length > 0 && ( <Overline className={styles.overline} type="subtle"> - <Text id="app.navigation.tabs.friends" /> —{" "} - {friends.length} + <Text id="app.status.offline" /> —{" "} + {offline.length} </Overline> )} - {friends.map(y => ( + {offline.map(y => ( <Friend key={y._id} user={y} /> ))} {blocked.length > 0 && (