parent
3afc068a02
commit
e51fc5a585
8 changed files with 202 additions and 2 deletions
|
@ -125,7 +125,7 @@ function EmojiVerificationContent({ data, requestClose }) {
|
|||
|
||||
return (
|
||||
<div className="emoji-verification__content">
|
||||
<Text>Click accept to start the verification process</Text>
|
||||
<Text>Click accept to start the verification process.</Text>
|
||||
<div className="emoji-verification__buttons">
|
||||
{
|
||||
process
|
||||
|
|
155
src/app/organisms/join-alias/JoinAlias.jsx
Normal file
155
src/app/organisms/join-alias/JoinAlias.jsx
Normal file
|
@ -0,0 +1,155 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './JoinAlias.scss';
|
||||
|
||||
import initMatrix from '../../../client/initMatrix';
|
||||
import cons from '../../../client/state/cons';
|
||||
import navigation from '../../../client/state/navigation';
|
||||
import { join } from '../../../client/action/room';
|
||||
import { selectRoom, selectSpace } from '../../../client/action/navigation';
|
||||
|
||||
import Text from '../../atoms/text/Text';
|
||||
import IconButton from '../../atoms/button/IconButton';
|
||||
import Button from '../../atoms/button/Button';
|
||||
import Input from '../../atoms/input/Input';
|
||||
import Spinner from '../../atoms/spinner/Spinner';
|
||||
import Dialog from '../../molecules/dialog/Dialog';
|
||||
|
||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
||||
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
|
||||
const ALIAS_OR_ID_REG = /^[#|!].+:.+\..+$/;
|
||||
|
||||
function JoinAliasContent({ term, requestClose }) {
|
||||
const [process, setProcess] = useState(false);
|
||||
const [error, setError] = useState(undefined);
|
||||
const [lastJoinId, setLastJoinId] = useState(undefined);
|
||||
|
||||
const mx = initMatrix.matrixClient;
|
||||
const mountStore = useStore();
|
||||
|
||||
const openRoom = (roomId) => {
|
||||
const room = mx.getRoom(roomId);
|
||||
if (!room) return;
|
||||
if (room.isSpaceRoom()) selectSpace(roomId);
|
||||
else selectRoom(roomId);
|
||||
requestClose();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleJoin = (roomId) => {
|
||||
if (lastJoinId !== roomId) return;
|
||||
openRoom(roomId);
|
||||
};
|
||||
initMatrix.roomList.on(cons.events.roomList.ROOM_JOINED, handleJoin);
|
||||
return () => {
|
||||
initMatrix.roomList.removeListener(cons.events.roomList.ROOM_JOINED, handleJoin);
|
||||
};
|
||||
}, [lastJoinId]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
mountStore.setItem(true);
|
||||
const alias = e.target.alias.value;
|
||||
if (alias?.trim() === '') return;
|
||||
if (alias.match(ALIAS_OR_ID_REG) === null) {
|
||||
setError('Invalid address.');
|
||||
return;
|
||||
}
|
||||
setProcess('Looking for address...');
|
||||
setError(undefined);
|
||||
let via;
|
||||
if (alias.startsWith('#')) {
|
||||
try {
|
||||
const aliasData = await mx.resolveRoomAlias(alias);
|
||||
via = aliasData?.servers || [];
|
||||
if (mountStore.getItem()) {
|
||||
setProcess(`Joining ${alias}...`);
|
||||
}
|
||||
} catch (err) {
|
||||
if (!mountStore.getItem()) return;
|
||||
setProcess(false);
|
||||
setError(`Unable to find room/space with ${alias}. Either room/space is private or doesn't exist.`);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const roomId = await join(alias, false, via);
|
||||
if (!mountStore.getItem()) return;
|
||||
setLastJoinId(roomId);
|
||||
openRoom(roomId);
|
||||
} catch {
|
||||
if (!mountStore.getItem()) return;
|
||||
setProcess(false);
|
||||
setError(`Unable to join ${alias}. Either room/space is private or doesn't exist.`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="join-alias" onSubmit={handleSubmit}>
|
||||
<Input
|
||||
label="Address"
|
||||
value={term}
|
||||
name="alias"
|
||||
required
|
||||
/>
|
||||
{error && <Text className="join-alias__error" variant="b3">{error}</Text>}
|
||||
<div className="join-alias__btn">
|
||||
{
|
||||
process
|
||||
? (
|
||||
<>
|
||||
<Spinner size="small" />
|
||||
<Text>{process}</Text>
|
||||
</>
|
||||
)
|
||||
: <Button variant="primary" type="submit">Join</Button>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
JoinAliasContent.defaultProps = {
|
||||
term: undefined,
|
||||
};
|
||||
JoinAliasContent.propTypes = {
|
||||
term: PropTypes.string,
|
||||
requestClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function useWindowToggle() {
|
||||
const [data, setData] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleOpen = (term) => {
|
||||
setData({ term });
|
||||
};
|
||||
navigation.on(cons.events.navigation.JOIN_ALIAS_OPENED, handleOpen);
|
||||
return () => {
|
||||
navigation.removeListener(cons.events.navigation.JOIN_ALIAS_OPENED, handleOpen);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onRequestClose = () => setData(null);
|
||||
|
||||
return [data, onRequestClose];
|
||||
}
|
||||
|
||||
function JoinAlias() {
|
||||
const [data, requestClose] = useWindowToggle();
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={data !== null}
|
||||
title={(
|
||||
<Text variant="s1" weight="medium" primary>Join with address</Text>
|
||||
)}
|
||||
contentOptions={<IconButton src={CrossIC} onClick={requestClose} tooltip="Close" />}
|
||||
onRequestClose={requestClose}
|
||||
>
|
||||
{ data ? <JoinAliasContent term={data.term} requestClose={requestClose} /> : <div /> }
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default JoinAlias;
|
20
src/app/organisms/join-alias/JoinAlias.scss
Normal file
20
src/app/organisms/join-alias/JoinAlias.scss
Normal file
|
@ -0,0 +1,20 @@
|
|||
@use '../../partials/dir';
|
||||
|
||||
.join-alias {
|
||||
padding: var(--sp-normal);
|
||||
@include dir.side(padding, var(--sp-normal), var(--sp-extra-tight));
|
||||
|
||||
& > *:not(:first-child) {
|
||||
margin-top: var(--sp-normal);
|
||||
}
|
||||
|
||||
&__error {
|
||||
color: var(--tc-danger-high);
|
||||
margin-top: var(--sp-extra-tight) !important;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
display: flex;
|
||||
gap: var(--sp-normal);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import { twemojify } from '../../../util/twemojify';
|
|||
import initMatrix from '../../../client/initMatrix';
|
||||
import cons from '../../../client/state/cons';
|
||||
import {
|
||||
openPublicRooms, openCreateRoom, openSpaceManage,
|
||||
openPublicRooms, openCreateRoom, openSpaceManage, openJoinAlias,
|
||||
openSpaceAddExisting, openInviteUser, openReusableContextMenu,
|
||||
} from '../../../client/action/navigation';
|
||||
import { getEventCords } from '../../../util/common';
|
||||
|
@ -60,6 +60,14 @@ export function HomeSpaceOptions({ spaceId, afterOptionSelect }) {
|
|||
Join public room
|
||||
</MenuItem>
|
||||
)}
|
||||
{ !spaceId && (
|
||||
<MenuItem
|
||||
iconSrc={PlusIC}
|
||||
onClick={() => { afterOptionSelect(); openJoinAlias(); }}
|
||||
>
|
||||
Join with address
|
||||
</MenuItem>
|
||||
)}
|
||||
{ spaceId && (
|
||||
<MenuItem
|
||||
iconSrc={PlusIC}
|
||||
|
|
|
@ -7,6 +7,7 @@ import SpaceAddExisting from '../../molecules/space-add-existing/SpaceAddExistin
|
|||
import Search from '../search/Search';
|
||||
import ViewSource from '../view-source/ViewSource';
|
||||
import CreateRoom from '../create-room/CreateRoom';
|
||||
import JoinAlias from '../join-alias/JoinAlias';
|
||||
import EmojiVerification from '../emoji-verification/EmojiVerification';
|
||||
|
||||
import ReusableDialog from '../../molecules/dialog/ReusableDialog';
|
||||
|
@ -19,6 +20,7 @@ function Dialogs() {
|
|||
<ProfileViewer />
|
||||
<ShortcutSpaces />
|
||||
<CreateRoom />
|
||||
<JoinAlias />
|
||||
<SpaceAddExisting />
|
||||
<Search />
|
||||
<EmojiVerification />
|
||||
|
|
|
@ -86,6 +86,13 @@ export function openCreateRoom(isSpace = false, parentId = null) {
|
|||
});
|
||||
}
|
||||
|
||||
export function openJoinAlias(term) {
|
||||
appDispatcher.dispatch({
|
||||
type: cons.actions.navigation.OPEN_JOIN_ALIAS,
|
||||
term,
|
||||
});
|
||||
}
|
||||
|
||||
export function openInviteUser(roomId, searchTerm) {
|
||||
appDispatcher.dispatch({
|
||||
type: cons.actions.navigation.OPEN_INVITE_USER,
|
||||
|
|
|
@ -38,6 +38,7 @@ const cons = {
|
|||
OPEN_INVITE_LIST: 'OPEN_INVITE_LIST',
|
||||
OPEN_PUBLIC_ROOMS: 'OPEN_PUBLIC_ROOMS',
|
||||
OPEN_CREATE_ROOM: 'OPEN_CREATE_ROOM',
|
||||
OPEN_JOIN_ALIAS: 'OPEN_JOIN_ALIAS',
|
||||
OPEN_INVITE_USER: 'OPEN_INVITE_USER',
|
||||
OPEN_PROFILE_VIEWER: 'OPEN_PROFILE_VIEWER',
|
||||
OPEN_SETTINGS: 'OPEN_SETTINGS',
|
||||
|
@ -86,6 +87,7 @@ const cons = {
|
|||
INVITE_LIST_OPENED: 'INVITE_LIST_OPENED',
|
||||
PUBLIC_ROOMS_OPENED: 'PUBLIC_ROOMS_OPENED',
|
||||
CREATE_ROOM_OPENED: 'CREATE_ROOM_OPENED',
|
||||
JOIN_ALIAS_OPENED: 'JOIN_ALIAS_OPENED',
|
||||
INVITE_USER_OPENED: 'INVITE_USER_OPENED',
|
||||
SETTINGS_OPENED: 'SETTINGS_OPENED',
|
||||
PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED',
|
||||
|
|
|
@ -122,6 +122,12 @@ class Navigation extends EventEmitter {
|
|||
action.parentId,
|
||||
);
|
||||
},
|
||||
[cons.actions.navigation.OPEN_JOIN_ALIAS]: () => {
|
||||
this.emit(
|
||||
cons.events.navigation.JOIN_ALIAS_OPENED,
|
||||
action.term,
|
||||
);
|
||||
},
|
||||
[cons.actions.navigation.OPEN_INVITE_USER]: () => {
|
||||
this.emit(cons.events.navigation.INVITE_USER_OPENED, action.roomId, action.searchTerm);
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue