refactor: share with element

reuse share selection component
pull/67/head
sualko 2020-08-29 10:33:59 +02:00
parent 971df674ec
commit f13f28afde
6 changed files with 59 additions and 190 deletions

View File

@ -0,0 +1,33 @@
.bbb-selection-container {
position: relative;
input {
width: 100%;
}
}
.bbb-selection {
position: absolute;
width: 100%;
background-color: #ffffff;
border: 1px solid var(--color-border-dark);
max-height: 88px;
overflow: auto;
box-shadow: 0 5px 10px -5px var(--color-box-shadow);
z-index: 100;
li {
color: var(--color-text-lighter);
padding: 0 1em;
line-height: 44px;
&.suggestion {
color: var(--color-main-text);
cursor: pointer;
&:hover {
background-color: var(--color-background-hover);
}
}
}
}

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { api, ShareWith, ShareType, ShareWithOption } from '../Common/Api';
import './ShareWith.scss';
import './ShareSelection.scss';
type Props = {
selectShare: (selection: ShareWithOption) => void;

View File

@ -35,43 +35,10 @@
}
}
.bbb-selection-container {
position: relative;
}
.bbb-selection {
position: absolute;
width: 100%;
background-color: #ffffff;
border: 1px solid var(--color-border-dark);
max-height: 88px;
overflow: auto;
box-shadow: 0 5px 10px -5px var(--color-box-shadow);
li {
color: var(--color-text-lighter);
padding: 0 1em;
line-height: 44px;
&.suggestion {
color: var(--color-main-text);
cursor: pointer;
&:hover {
background-color: var(--color-background-hover);
}
}
}
}
.bbb-form-shareWith {
margin-top: -1.5em;
}
.bbb-icon-unselected {
opacity: 0.2 !important;
&:hover {
opacity: 0.5 !important;
}
}
}

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { api, ShareWith, ShareType, RoomShare, Room, Permission, ShareWithOption } from '../Common/Api';
import React from 'react';
import { api, ShareWith, ShareType, RoomShare, Room, Permission } from '../Common/Api';
import './ShareWith.scss';
import ShareSelection from '../Common/ShareSelection';
type Props = {
room: Room;
@ -10,12 +11,6 @@ type Props = {
}
const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setShares }) => {
const [search, setSearch] = useState<string>('');
const [hasFocus, setFocus] = useState<boolean>(false);
const [showSearchResults, setShowSearchResults] = useState<boolean>(false);
const [recommendations, setRecommendations] = useState<ShareWith>();
const [searchResults, setSearchResults] = useState<ShareWith>();
const isOwner = room.userId === OC.currentUser;
const shares = (allShares && permission === Permission.Moderator) ?
@ -24,32 +19,11 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
const sharedUserIds = shares ? shares.filter(share => share.shareType === ShareType.User).map(share => share.shareWith) : [];
const sharedGroupIds = shares ? shares.filter(share => share.shareType === ShareType.Group).map(share => share.shareWith) : [];
useEffect(() => {
setSearchResults(undefined);
const searchQuery = search;
api.searchShareWith(searchQuery).then(result => {
if (searchQuery === search) {
setSearchResults(result);
}
});
}, [search]);
useEffect(() => {
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);
roomShare.shareWithDisplayName = displayName;
console.log('addRoomShare', allShares, roomShare);
const newShares = allShares ? [...allShares] : [];
const index = newShares.findIndex(share => share.id === roomShare.id);
@ -59,10 +33,7 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
newShares.push(roomShare);
}
console.log('newroomshares', newShares);
setShares(newShares);
setSearch('');
}
async function deleteRoomShare(id: number) {
@ -79,27 +50,12 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
return addRoomShare(share.shareWith, share.shareType, share.shareWithDisplayName || share.shareWith, newPermission);
}
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 (
<ul className="bbb-selection">
{!options ?
<li><span className="icon icon-loading-small icon-visible"></span> {t('bbb', 'Searching')}</li> :
(
(results.length === 0 && search) ? <li>{t('bbb', 'No matches')}</li> : results.map(renderOption)
)}
</ul>
);
function getAvatarUrl(userId: string) {
return OC.generateUrl('/avatar/' + encodeURIComponent(userId) + '/' + 32, {
user: userId,
size: 32,
requesttoken: OC.requestToken,
});
}
function renderShares(shares: RoomShare[]) {
@ -116,11 +72,7 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
return (
<ul className="bbb-shareWith">
{[ownShare, ...shares].map(share => {
const avatarUrl = share.shareType === ShareType.User ? OC.generateUrl('/avatar/' + encodeURIComponent(share.shareWith) + '/' + 32, {
user: share.shareWith,
size: 32,
requesttoken: OC.requestToken,
}) : undefined;
const avatarUrl = share.shareType === ShareType.User ? getAvatarUrl(share.shareWith) : undefined;
const displayName = share.shareWithDisplayName || share.shareWith;
return (
@ -136,7 +88,10 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
</div>
{(share.id > -1 && permission === Permission.Moderator && isOwner) && <div className="bbb-shareWith__item__action">
<a className={`icon icon-shared icon-visible ${share.permission === Permission.Admin ? 'bbb-icon-selected' : 'bbb-icon-unselected'}`}
onClick={ev => {ev.preventDefault(); toggleAdminShare(share);}}
onClick={ev => {
ev.preventDefault();
toggleAdminShare(share);
}}
title={t('bbb', 'Share')} />
</div>}
{(share.id > -1 && isOwner) && <div className="bbb-shareWith__item__action">
@ -157,17 +112,14 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
<>
{shares ? renderShares(shares) : loading}
<div className="bbb-selection-container">
{isOwner ? <input
type="text"
value={search}
onChange={ev => setSearch(ev.currentTarget.value)}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
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>}
{showSearchResults && renderSearchResults((search && searchResults) ? searchResults : ((recommendations && !search) ? recommendations : undefined))}
</div>
{isOwner ?
<ShareSelection
selectShare={(shareOption) => addRoomShare(shareOption.value.shareWith, shareOption.value.shareType, shareOption.label, permission)}
excluded={{userIds: sharedUserIds, groupIds: sharedGroupIds}}/> :
<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>
}
</>
);
};

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import '../Manager/App.scss';
import { api, Restriction, ShareType } from '../Common/Api';
import RestrictionRow from './RestrictionRow';
import ShareSelection from './ShareSelection';
import ShareSelection from '../Common/ShareSelection';
type Props = {
@ -52,8 +52,7 @@ const App: React.FC<Props> = () => {
}
return (
<div id="bbb-react-root"
onClick={() => { /* @TODO hide edit inputs */ }}>
<div id="bbb-react-root">
<table>
<thead>
<tr>

View File

@ -1,82 +0,0 @@
.bbb-shareWith {
margin: 1em 0;
&__item {
height: 44px;
display: flex;
align-items: center;
&:hover {
background-color: var(--color-background-dark);
}
.avatardiv {
height: 32px;
width: 32px;
overflow: hidden;
.icon-group-white {
display: block;
height: 100%;
width: 100%;
background-color: #a9a9a9;
}
}
.icon {
height: 44px;
width: 44px;
}
&__label {
padding: 0 1em;
flex-grow: 1;
}
}
}
.bbb-selection-container {
position: relative;
input {
width: 100%;
}
}
.bbb-selection {
position: absolute;
width: 100%;
background-color: #ffffff;
border: 1px solid var(--color-border-dark);
max-height: 88px;
overflow: auto;
box-shadow: 0 5px 10px -5px var(--color-box-shadow);
z-index: 100;
li {
color: var(--color-text-lighter);
padding: 0 1em;
line-height: 44px;
&.suggestion {
color: var(--color-main-text);
cursor: pointer;
&:hover {
background-color: var(--color-background-hover);
}
}
}
}
.bbb-form-shareWith {
margin-top: -1.5em;
}
.bbb-icon-unselected {
opacity: 0.2 !important;
&:hover {
opacity: 0.5 !important;
}
}