fix: improve share with input

- show loading indicator (fix #58)
- fix drop down behaviour (fix #49)
pull/67/head
sualko 2020-08-25 15:18:10 +02:00
parent ab60034086
commit bfbf130e3f
3 changed files with 50 additions and 31 deletions

View File

@ -47,21 +47,17 @@ export type Recording = {
meta: any; meta: any;
} }
export interface ShareWithOption {
label: string;
value: {
shareType: ShareType;
shareWith: string;
};
}
export interface ShareWith { export interface ShareWith {
users: { users: ShareWithOption[];
label: string; groups: ShareWithOption[];
value: {
shareType: ShareType;
shareWith: string;
};
}[];
groups: {
label: string;
value: {
shareType: ShareType;
shareWith: string;
};
}[];
} }
class Api { class Api {

View File

@ -49,12 +49,17 @@
box-shadow: 0 5px 10px -5px var(--color-box-shadow); box-shadow: 0 5px 10px -5px var(--color-box-shadow);
li { li {
color: var(--color-text-lighter);
padding: 0 1em; padding: 0 1em;
cursor: pointer;
line-height: 44px; line-height: 44px;
&:hover { &.suggestion {
background-color: var(--color-background-hover); color: var(--color-main-text);
cursor: pointer;
&:hover {
background-color: var(--color-background-hover);
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { api, ShareWith, ShareType, RoomShare, Room, Permission } from './Api'; import { api, ShareWith, ShareType, RoomShare, Room, Permission, ShareWithOption } from './Api';
import './ShareWith.scss'; import './ShareWith.scss';
type Props = { type Props = {
@ -12,6 +12,7 @@ type Props = {
const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setShares }) => { const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setShares }) => {
const [search, setSearch] = useState<string>(''); const [search, setSearch] = useState<string>('');
const [hasFocus, setFocus] = useState<boolean>(false); const [hasFocus, setFocus] = useState<boolean>(false);
const [showSearchResults, setShowSearchResults] = useState<boolean>(false);
const [recommendations, setRecommendations] = useState<ShareWith>(); const [recommendations, setRecommendations] = useState<ShareWith>();
const [searchResults, setSearchResults] = useState<ShareWith>(); const [searchResults, setSearchResults] = useState<ShareWith>();
@ -24,8 +25,13 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
const sharedGroupIds = shares ? shares.filter(share => share.shareType === ShareType.Group).map(share => share.shareWith) : []; const sharedGroupIds = shares ? shares.filter(share => share.shareType === ShareType.Group).map(share => share.shareWith) : [];
useEffect(() => { useEffect(() => {
api.searchShareWith(search).then(result => { setSearchResults(undefined);
setSearchResults(result); const searchQuery = search;
api.searchShareWith(searchQuery).then(result => {
if (searchQuery === search) {
setSearchResults(result);
}
}); });
}, [search]); }, [search]);
@ -33,6 +39,10 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
api.getRecommendedShareWith().then(result => setRecommendations(result)); api.getRecommendedShareWith().then(result => setRecommendations(result));
}, []); }, []);
useEffect(() => {
setTimeout(() => setShowSearchResults(hasFocus), 100);
}, [hasFocus]);
async function addRoomShare(shareWith: string, shareType: number, displayName: string, permission: Permission) { async function addRoomShare(shareWith: string, shareType: number, displayName: string, permission: Permission) {
const roomShare = await api.createRoomShare(room.id, shareType, shareWith, permission); const roomShare = await api.createRoomShare(room.id, shareType, shareWith, permission);
@ -68,17 +78,25 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
return addRoomShare(share.shareWith, share.shareType, share.shareWithDisplayName || share.shareWith, newPermission); return addRoomShare(share.shareWith, share.shareType, share.shareWithDisplayName || share.shareWith, newPermission);
} }
function renderSearchResults(options: ShareWith) { function renderSearchResults(options: ShareWith|undefined) {
const results = options ? [
...options.users.filter(user => !sharedUserIds.includes(user.value.shareWith)),
...options.groups.filter(group => !sharedGroupIds.includes(group.value.shareWith)),
] : [];
const renderOption = (option: ShareWithOption) => {
return (<li key={option.value.shareWith} className="suggestion" onClick={() => addRoomShare(option.value.shareWith, option.value.shareType, option.label, permission)}>
{option.label}{option.value.shareType === ShareType.Group ? ` (${t('bbb', 'Group')})` : ''}
</li>);
};
return ( return (
<ul className="bbb-selection"> <ul className="bbb-selection">
{[ {!options ?
...options.users.filter(user => !sharedUserIds.includes(user.value.shareWith)), <li><span className="icon icon-loading-small icon-visible"></span> {t('bbb', 'Searching')}</li> :
...options.groups.filter(group => !sharedGroupIds.includes(group.value.shareWith)), (
].map(option => { (results.length === 0 && search) ? <li>{t('bbb', 'No matches')}</li> : results.map(renderOption)
return (<li key={option.value.shareWith} onClick={() => addRoomShare(option.value.shareWith, option.value.shareType, option.label, permission)}> )}
{option.label}{option.value.shareType === ShareType.Group ? ` (${t('bbb', 'Group')})` : ''}
</li>);
})}
</ul> </ul>
); );
} }
@ -144,10 +162,10 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
value={search} value={search}
onChange={ev => setSearch(ev.currentTarget.value)} onChange={ev => setSearch(ev.currentTarget.value)}
onFocus={() => setFocus(true)} onFocus={() => setFocus(true)}
onBlur={() => setTimeout(() => setFocus(false), 100)} onBlur={() => setFocus(false)}
placeholder={t('bbb', 'Name, group, ...')} /> : placeholder={t('bbb', 'Name, group, ...')} /> :
<em><span className="icon icon-details icon-visible"></span> {t('bbb', 'You are not allowed to change this option, because this room is shared with you.')}</em>} <em><span className="icon icon-details icon-visible"></span> {t('bbb', 'You are not allowed to change this option, because this room is shared with you.')}</em>}
{hasFocus && (searchResults ? renderSearchResults(searchResults) : (recommendations ? renderSearchResults(recommendations) : loading))} {showSearchResults && renderSearchResults((search && searchResults) ? searchResults : ((recommendations && !search) ? recommendations : undefined))}
</div> </div>
</> </>
); );