From bfbf130e3fae6a4120e41403d08cfaf5222c5fa7 Mon Sep 17 00:00:00 2001 From: sualko Date: Tue, 25 Aug 2020 15:18:10 +0200 Subject: [PATCH] fix: improve share with input - show loading indicator (fix #58) - fix drop down behaviour (fix #49) --- ts/Manager/Api.ts | 24 +++++++++----------- ts/Manager/ShareWith.scss | 11 +++++++--- ts/Manager/ShareWith.tsx | 46 +++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/ts/Manager/Api.ts b/ts/Manager/Api.ts index e33f116..f2b20ad 100644 --- a/ts/Manager/Api.ts +++ b/ts/Manager/Api.ts @@ -47,21 +47,17 @@ export type Recording = { meta: any; } +export interface ShareWithOption { + label: string; + value: { + shareType: ShareType; + shareWith: string; + }; +} + export interface ShareWith { - users: { - label: string; - value: { - shareType: ShareType; - shareWith: string; - }; - }[]; - groups: { - label: string; - value: { - shareType: ShareType; - shareWith: string; - }; - }[]; + users: ShareWithOption[]; + groups: ShareWithOption[]; } class Api { diff --git a/ts/Manager/ShareWith.scss b/ts/Manager/ShareWith.scss index 71f6047..1101b2e 100644 --- a/ts/Manager/ShareWith.scss +++ b/ts/Manager/ShareWith.scss @@ -49,12 +49,17 @@ box-shadow: 0 5px 10px -5px var(--color-box-shadow); li { + color: var(--color-text-lighter); padding: 0 1em; - cursor: pointer; line-height: 44px; - &:hover { - background-color: var(--color-background-hover); + &.suggestion { + color: var(--color-main-text); + cursor: pointer; + + &:hover { + background-color: var(--color-background-hover); + } } } } diff --git a/ts/Manager/ShareWith.tsx b/ts/Manager/ShareWith.tsx index 30d2b98..00206fc 100644 --- a/ts/Manager/ShareWith.tsx +++ b/ts/Manager/ShareWith.tsx @@ -1,5 +1,5 @@ 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'; type Props = { @@ -12,6 +12,7 @@ type Props = { const ShareWith: React.FC = ({ room, permission, shares: allShares, setShares }) => { const [search, setSearch] = useState(''); const [hasFocus, setFocus] = useState(false); + const [showSearchResults, setShowSearchResults] = useState(false); const [recommendations, setRecommendations] = useState(); const [searchResults, setSearchResults] = useState(); @@ -24,8 +25,13 @@ const ShareWith: React.FC = ({ room, permission, shares: allShares, setSh const sharedGroupIds = shares ? shares.filter(share => share.shareType === ShareType.Group).map(share => share.shareWith) : []; useEffect(() => { - api.searchShareWith(search).then(result => { - setSearchResults(result); + setSearchResults(undefined); + const searchQuery = search; + + api.searchShareWith(searchQuery).then(result => { + if (searchQuery === search) { + setSearchResults(result); + } }); }, [search]); @@ -33,6 +39,10 @@ const ShareWith: React.FC = ({ room, permission, shares: allShares, setSh api.getRecommendedShareWith().then(result => setRecommendations(result)); }, []); + useEffect(() => { + setTimeout(() => setShowSearchResults(hasFocus), 100); + }, [hasFocus]); + async function addRoomShare(shareWith: string, shareType: number, displayName: string, permission: Permission) { const roomShare = await api.createRoomShare(room.id, shareType, shareWith, permission); @@ -68,17 +78,25 @@ const ShareWith: React.FC = ({ room, permission, shares: allShares, setSh 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 (
  • addRoomShare(option.value.shareWith, option.value.shareType, option.label, permission)}> + {option.label}{option.value.shareType === ShareType.Group ? ` (${t('bbb', 'Group')})` : ''} +
  • ); + }; + return (
      - {[ - ...options.users.filter(user => !sharedUserIds.includes(user.value.shareWith)), - ...options.groups.filter(group => !sharedGroupIds.includes(group.value.shareWith)), - ].map(option => { - return (
    • addRoomShare(option.value.shareWith, option.value.shareType, option.label, permission)}> - {option.label}{option.value.shareType === ShareType.Group ? ` (${t('bbb', 'Group')})` : ''} -
    • ); - })} + {!options ? +
    • {t('bbb', 'Searching')}
    • : + ( + (results.length === 0 && search) ?
    • {t('bbb', 'No matches')}
    • : results.map(renderOption) + )}
    ); } @@ -144,10 +162,10 @@ const ShareWith: React.FC = ({ room, permission, shares: allShares, setSh value={search} onChange={ev => setSearch(ev.currentTarget.value)} onFocus={() => setFocus(true)} - onBlur={() => setTimeout(() => setFocus(false), 100)} + onBlur={() => setFocus(false)} placeholder={t('bbb', 'Name, group, ...')} /> : {t('bbb', 'You are not allowed to change this option, because this room is shared with you.')}} - {hasFocus && (searchResults ? renderSearchResults(searchResults) : (recommendations ? renderSearchResults(recommendations) : loading))} + {showSearchResults && renderSearchResults((search && searchResults) ? searchResults : ((recommendations && !search) ? recommendations : undefined))} );