From 74b790927eadfeca8b4bf816a51c87c36eba67ed Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Sun, 13 Sep 2020 17:39:39 +0100 Subject: [PATCH] Show sharer preview for matrix.to links --- src/components/DefaultPreview.scss | 4 ++ src/components/LinkPreview.tsx | 54 ++++++++++--------------- src/components/UserPreview.tsx | 64 ++++++++++++++++++++++++------ src/contexts/HSContext.ts | 16 +------- src/utils/getHS.ts | 52 ++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 62 deletions(-) create mode 100644 src/utils/getHS.ts diff --git a/src/components/DefaultPreview.scss b/src/components/DefaultPreview.scss index 21b77bb..48e404c 100644 --- a/src/components/DefaultPreview.scss +++ b/src/components/DefaultPreview.scss @@ -19,4 +19,8 @@ limitations under the License. border-radius: 0; border: 0; } + + h1 { + word-break: break-all; + } } diff --git a/src/components/LinkPreview.tsx b/src/components/LinkPreview.tsx index bcdb7be..618de53 100644 --- a/src/components/LinkPreview.tsx +++ b/src/components/LinkPreview.tsx @@ -20,10 +20,11 @@ import { getEvent, client } from 'matrix-cypher'; import { RoomPreviewWithTopic } from './RoomPreview'; import InviteTile from './InviteTile'; import { SafeLink, LinkKind } from '../parser/types'; -import UserPreview from './UserPreview'; +import UserPreview, { WrappedInviterPreview } from './UserPreview'; import EventPreview from './EventPreview'; import HomeserverOptions from './HomeserverOptions'; import DefaultPreview from './DefaultPreview'; +import Toggle from './Toggle'; import { clientMap } from '../clients'; import { getRoomFromId, @@ -32,12 +33,7 @@ import { getUser, } from '../utils/cypher-wrapper'; import { ClientContext } from '../contexts/ClientContext'; -import HSContext, { - TempHSContext, - HSOptions, - State as HSState, -} from '../contexts/HSContext'; -import Toggle from './Toggle'; +import useHSs from '../utils/getHS'; interface IProps { link: SafeLink; @@ -118,32 +114,14 @@ const Preview: React.FC = ({ link, client }: PreviewProps) => { return content; }; -function selectedClient(link: SafeLink, hsOptions: HSState): string[] { - switch (hsOptions.option) { - case HSOptions.Unset: - return []; - case HSOptions.None: - return []; - case HSOptions.TrustedHSOnly: - return [hsOptions.hs]; - case HSOptions.Any: - return [ - 'https://' + link.identifier.split(':')[1], - ...link.arguments.vias, - ]; - } -} - const LinkPreview: React.FC = ({ link }: IProps) => { let content: JSX.Element; const [showHSOptions, setShowHSOPtions] = useState(false); - const [hsOptions] = useContext(HSContext); - const [tempHSState] = useContext(TempHSContext); - if ( - hsOptions.option === HSOptions.Unset && - tempHSState.option === HSOptions.Unset - ) { + const hses = useHSs(link); + console.log(hses); + + if (!hses) { content = ( <> @@ -164,11 +142,7 @@ const LinkPreview: React.FC = ({ link }: IProps) => { ); } } else { - const clients = - tempHSState.option !== HSOptions.Unset - ? selectedClient(link, tempHSState) - : selectedClient(link, hsOptions); - content = ; + content = ; } const [{ clientId }] = useContext(ClientContext); @@ -182,8 +156,20 @@ const LinkPreview: React.FC = ({ link }: IProps) => { const client = displayClientId ? clientMap[displayClientId] : null; + const sharer = link.arguments.sharer ? ( + + ) : null; + return ( + {sharer} {content} ); diff --git a/src/components/UserPreview.tsx b/src/components/UserPreview.tsx index 415b2a2..af9a440 100644 --- a/src/components/UserPreview.tsx +++ b/src/components/UserPreview.tsx @@ -14,10 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import { User } from 'matrix-cypher'; +import React, { useState, useEffect } from 'react'; +import { client, User, getUserDetails } from 'matrix-cypher'; +import icon from '../imgs/chat-icon.svg'; -import { UserAvatar } from './Avatar'; +import Avatar, { UserAvatar } from './Avatar'; +import useHSs from '../utils/getHS'; +import { UserId } from '../parser/types'; import './UserPreview.scss'; @@ -37,14 +40,49 @@ const UserPreview: React.FC = ({ user, userId }: IProps) => ( export default UserPreview; -export const InviterPreview: React.FC = ({ user, userId }: IProps) => ( -
-
-

- Invited by {user.displayname} -

-

{userId}

-
+interface InviterPreviewProps { + user?: User; + userId: string; +} + +export const InviterPreview: React.FC = ({ + user, + userId, +}: InviterPreviewProps) => { + const avatar = user ? ( -
-); + ) : ( + + ); + return ( +
+
+

+ Invited by {user ? user.displayname : userId} +

+ {user ?

{userId}

: null} +
+ {avatar} +
+ ); +}; + +interface WrappedInviterProps { + link: UserId; +} + +export const WrappedInviterPreview: React.FC = ({ + link, +}: WrappedInviterProps) => { + const [user, setUser] = useState(undefined); + const hss = useHSs(link); + useEffect(() => { + if (hss) { + client(hss[0]) + .then((c) => getUserDetails(c, link.identifier)) + .then(setUser) + .catch((x) => console.log("couldn't fetch user preview", x)); + } + }, [hss, link]); + return ; +}; diff --git a/src/contexts/HSContext.ts b/src/contexts/HSContext.ts index 686ba05..c6b5201 100644 --- a/src/contexts/HSContext.ts +++ b/src/contexts/HSContext.ts @@ -29,17 +29,12 @@ export enum HSOptions { TrustedHSOnly = 'TRUSTED_CLIENT_ONLY', // Matrix.to may contact any homeserver it requires Any = 'ANY', - // Matrix.to may not contact any homeservers - None = 'NONE', } const STATE_SCHEMA = union([ object({ option: literal(HSOptions.Unset), }), - object({ - option: literal(HSOptions.None), - }), object({ option: literal(HSOptions.Any), }), @@ -55,7 +50,6 @@ export type State = TypeOf; export enum ActionType { SetHS = 'SET_HS', SetAny = 'SET_ANY', - SetNone = 'SET_NONE', } export interface SetHS { @@ -67,11 +61,7 @@ export interface SetAny { action: ActionType.SetAny; } -export interface SetNone { - action: ActionType.SetNone; -} - -export type Action = SetHS | SetAny | SetNone; +export type Action = SetHS | SetAny; export const INITIAL_STATE: State = { option: HSOptions.Unset, @@ -81,10 +71,6 @@ export const unpersistedReducer = (state: State, action: Action): State => { console.log('reducing'); console.log(action); switch (action.action) { - case ActionType.SetNone: - return { - option: HSOptions.None, - }; case ActionType.SetAny: return { option: HSOptions.Any, diff --git a/src/utils/getHS.ts b/src/utils/getHS.ts new file mode 100644 index 0000000..b8239da --- /dev/null +++ b/src/utils/getHS.ts @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { useContext } from 'react'; +import HSContext, { + TempHSContext, + State, + HSOptions, +} from '../contexts/HSContext'; +import { SafeLink } from '../parser/types'; + +function selectedClient(link: SafeLink, hsOptions: State): string[] { + switch (hsOptions.option) { + case HSOptions.Unset: + return []; + case HSOptions.TrustedHSOnly: + return [hsOptions.hs]; + case HSOptions.Any: + return [ + ...link.identifier + .split('/') + .map((i) => 'https://' + i.split(':')[1]), + ...link.arguments.vias, + ]; + } +} + +export default function useHSs(link: SafeLink): string[] { + const [HSState] = useContext(HSContext); + const [TempHSState] = useContext(TempHSContext); + + if (HSState.option !== HSOptions.Unset) { + return selectedClient(link, HSState); + } else if (TempHSState.option !== HSOptions.Unset) { + return selectedClient(link, TempHSState); + } else { + return []; + } +}