Web: Client: Added base invite panel

This commit is contained in:
Ilya Oleshko 2022-08-29 08:50:37 +03:00
parent e2472b392e
commit 4092aa546a
9 changed files with 423 additions and 4 deletions

View File

@ -10,6 +10,7 @@ import {
NewFilesPanel,
SelectFileDialog,
HotkeyPanel,
InvitePanel,
} from "../panels";
import {
ThirdPartyMoveDialog,
@ -46,6 +47,7 @@ const Panels = (props) => {
selectFileDialogVisible,
setSelectFileDialogVisible,
hotkeyPanelVisible,
invitePanelVisible,
convertPasswordDialogVisible,
} = props;
@ -103,6 +105,7 @@ const Panels = (props) => {
/>
),
hotkeyPanelVisible && <HotkeyPanel key="hotkey-panel" />,
invitePanelVisible && <InvitePanel key="invite-panel" />,
convertPasswordDialogVisible && (
<ConvertPasswordDialog key="convert-password-dialog" />
),
@ -136,7 +139,7 @@ export default inject(
const { uploadPanelVisible } = uploadDataStore;
const { isVisible: versionHistoryPanelVisible } = versionHistoryStore;
const { hotkeyPanelVisible } = auth.settingsStore;
const { hotkeyPanelVisible, invitePanelVisible } = auth.settingsStore;
return {
sharingPanelVisible,
@ -160,6 +163,7 @@ export default inject(
createMasterForm,
setSelectFileDialogVisible,
hotkeyPanelVisible,
invitePanelVisible,
};
}
)(observer(Panels));

View File

@ -0,0 +1,85 @@
import React, { useState, useCallback, useEffect, useRef } from "react";
import debounce from "lodash.debounce";
import Avatar from "@docspace/components/avatar";
import {
StyledInviteInput,
StyledInviteInputContainer,
StyledDropDown,
StyledDropDownItem,
SearchItemText,
} from "./StyledInvitePanel";
const InviteInput = ({ onAddUser, getUsersList }) => {
const [inputValue, setInputValue] = useState("");
const [usersList, setUsersList] = useState([]);
const [panelVisible, setPanelVisible] = useState(false);
const toUserItem = (email) => {
const uid = () =>
String(Date.now().toString(32) + Math.random().toString(16)).replace(
/\./g,
""
);
return {
email,
id: uid(),
displayName: email,
};
};
const searchByTerm = async (value) => {
const users = await getUsersList();
setUsersList(users);
//const user = toUserItem(value);
//onAddUser && onAddUser(user);
};
const debouncedSearch = useCallback(
debounce((value) => searchByTerm(value), 1000),
[]
);
const onChange = (e) => {
const value = e.target.value;
setPanelVisible(value.length > 0);
setInputValue(value);
debouncedSearch(value);
};
const getItemContent = (item) => {
const { avatarSmall, displayName, email, id } = item;
return (
<StyledDropDownItem key={id}>
<Avatar size="min" role="user" source={avatarSmall} />
<div>
<SearchItemText primary>{displayName}</SearchItemText>
<SearchItemText>{email}</SearchItemText>
</div>
<SearchItemText info>Invited</SearchItemText>
</StyledDropDownItem>
);
};
return (
<StyledInviteInputContainer>
<StyledInviteInput
onChange={onChange}
placeholder="Invite people by name or email"
value={inputValue}
/>
<StyledDropDown isDefaultMode={false} open={panelVisible} manualX="16px">
{usersList?.map((user) => getItemContent(user))}
</StyledDropDown>
</StyledInviteInputContainer>
);
};
export default InviteInput;

View File

@ -0,0 +1,117 @@
import styled from "styled-components";
import Heading from "@docspace/components/heading";
import TextInput from "@docspace/components/text-input";
import ComboBox from "@docspace/components/combobox";
import Box from "@docspace/components/box";
import DropDown from "@docspace/components/drop-down";
import DropDownItem from "@docspace/components/drop-down-item";
import Text from "@docspace/components/text";
import { Base } from "@docspace/components/themes";
const StyledInvitePanel = styled.div``;
const StyledBlock = styled.div`
padding: ${(props) => (props.noPadding ? "0px" : "0 16px")};
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
`;
StyledBlock.defaultProps = { theme: Base };
const fillAvailableWidth = `
width: 100%;
width: -moz-available;
width: -webkit-fill-available;
width: fill-available;
`;
const StyledHeading = styled(Heading)`
font-weight: 700;
font-size: 18px;
`;
const StyledSubHeader = styled(Heading)`
font-weight: 700;
font-size: 16px;
padding-left: 16px;
margin: 20px 0;
`;
const StyledRow = styled.div`
${fillAvailableWidth}
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 41px;
margin-left: 16px;
box-sizing: border-box;
border-bottom: none;
a {
font-weight: 600;
font-size: 14px;
line-height: 16px;
}
`;
const StyledInviteInput = styled(TextInput)`
${fillAvailableWidth}
margin-left: 16px;
margin-bottom: 20px;
`;
const StyledComboBox = styled(ComboBox)`
margin-left: auto;
.combo-button-label,
.combo-button-label:hover {
text-decoration: none;
}
`;
const StyledInviteInputContainer = styled(Box)`
position: relative;
`;
const StyledDropDown = styled(DropDown)`
${fillAvailableWidth}
`;
const StyledDropDownItem = styled(DropDownItem)`
display: flex;
align-items: center;
gap: 8px;
height: 48px;
`;
const SearchItemText = styled(Text)`
line-height: 16px;
font-size: ${(props) =>
props.primary ? "14px" : props.info ? "11px" : "12px"};
font-weight: ${(props) => (props.primary || props.info ? "600" : "400")};
color: ${(props) =>
props.primary || props.info
? props.theme.text.color
: props.theme.text.disableColor};
${(props) => props.info && `margin-left: auto`}
`;
StyledBlock.defaultProps = { theme: Base };
export {
StyledBlock,
StyledHeading,
StyledInvitePanel,
StyledRow,
StyledSubHeader,
StyledInviteInput,
StyledComboBox,
StyledInviteInputContainer,
StyledDropDown,
StyledDropDownItem,
SearchItemText,
};

View File

@ -0,0 +1,127 @@
import React, { useEffect, useState } from "react";
import debounce from "lodash.debounce";
import { observer, inject } from "mobx-react";
import { withTranslation } from "react-i18next";
import Backdrop from "@docspace/components/backdrop";
import Aside from "@docspace/components/aside";
import Base from "@docspace/components/themes/base";
import {
StyledBlock,
StyledHeading,
StyledInvitePanel,
StyledSubHeader,
StyledInviteInput,
} from "./StyledInvitePanel";
import Items from "./items.js";
import InviteInput from "./InviteInput";
const InvitePanel = ({
invitePanelVisible,
setInvitePanelVisible,
t,
theme,
tReady,
getUsersList,
}) => {
const testItems = [
{
email: "test1@gmail.com",
id: "1",
displayName: "Administrator Test1",
avatarSmall:
"/storage/userPhotos/root/66faa6e4-f133-11ea-b126-00ffeec8b4ef_orig_46-46.jpeg?_=1380485370",
},
{
email: "test2@gmail.com",
id: "2",
displayName: "Administrator Test2",
avatarSmall:
"/storage/userPhotos/root/66faa6e4-f133-11ea-b126-00ffeec8b4ef_orig_46-46.jpeg?_=1380485370",
},
{
email: "test3@gmail.com",
id: "3",
displayName: "Administrator Test3",
},
{
email: "test4@gmail.com",
id: "4",
displayName: "Administrator Test4",
},
];
const [items, setItems] = useState(testItems);
const onClose = () => setInvitePanelVisible(false);
const onAddUser = (user) => {
setItems([...items, user]);
};
const onKeyPress = (e) =>
(e.key === "Esc" || e.key === "Escape") && onClose();
useEffect(() => {
document.addEventListener("keyup", onKeyPress);
return () => document.removeEventListener("keyup", onKeyPress);
});
const onSelectItemAccess = (selectedItem) => {
if (selectedItem.key === "delete") {
const newItems = items.filter((item) => item.id !== selectedItem.id);
return setItems(newItems);
}
};
return (
<StyledInvitePanel>
<Backdrop
onClick={onClose}
visible={invitePanelVisible}
isAside={true}
zIndex={210}
/>
<Aside
className="invite_panel"
visible={invitePanelVisible}
onClose={onClose}
>
<StyledBlock>
<StyledHeading>Invite users to the room</StyledHeading>
</StyledBlock>
<StyledBlock noPadding>
<StyledSubHeader>External link</StyledSubHeader>
</StyledBlock>
<StyledSubHeader>Individual invitation</StyledSubHeader>
<InviteInput getUsersList={getUsersList} onAddUser={onAddUser} />
<Items items={items} onSelectItemAccess={onSelectItemAccess} />
</Aside>
</StyledInvitePanel>
);
};
InvitePanel.defaultProps = { theme: Base };
export default inject(({ auth, peopleStore }) => {
const {
invitePanelVisible,
setInvitePanelVisible,
theme,
} = auth.settingsStore;
const { getUsersList } = peopleStore.usersStore;
return {
invitePanelVisible,
setInvitePanelVisible,
theme,
getUsersList,
};
})(
withTranslation(["HotkeysPanel", "Article", "Common"])(observer(InvitePanel))
);

View File

@ -0,0 +1,78 @@
import React from "react";
import Text from "@docspace/components/text";
import Avatar from "@docspace/components/avatar";
import { StyledRow, StyledComboBox } from "./StyledInvitePanel";
const Items = ({ t, items, onSelectItemAccess }) => {
const getAccesses = (id) => {
return [
{
key: "roomManager",
label: "Room manager",
id,
},
{
key: "editor",
label: "Editor",
id,
},
{
key: "formFiller",
label: "Form filler",
id,
},
{
key: "reviewer",
label: "Reviewer",
id,
},
{
key: "commentator",
label: "Commentator",
id,
},
{
key: "viewer",
label: "Viewer",
id,
},
{
key: "sep",
isSeparator: true,
id,
},
{
key: "delete",
label: "Delete",
id,
},
];
};
return items.map((item) => {
const { avatarSmall, displayName, email, id } = item;
const name = !!avatarSmall ? displayName : email;
const source = !!avatarSmall ? avatarSmall : "/static/images/@.react.svg";
const options = getAccesses(id);
return (
<StyledRow key={id}>
<Avatar size="min" role="user" source={source} />
<Text>{name}</Text>
<StyledComboBox
onSelect={onSelectItemAccess}
noBorder
options={options}
size="content"
scaled={false}
manualWidth="fit-content"
selectedOption={options[5]}
showDisabledItems
/>
</StyledRow>
);
});
};
export default Items;

View File

@ -9,6 +9,7 @@ import ChangeOwnerPanel from "./ChangeOwnerPanel";
import UploadPanel from "./UploadPanel";
import SelectFileDialog from "./SelectFileDialog";
import HotkeyPanel from "./HotkeysPanel";
import InvitePanel from "./InvitePanel";
export {
SharingPanel,
@ -22,4 +23,5 @@ export {
UploadPanel,
SelectFileDialog,
HotkeyPanel,
InvitePanel,
};

View File

@ -345,8 +345,8 @@ class ContextOptionsStore {
console.log("edit room");
};
onClickInviteUsers = () => {
console.log("invite users");
onClickInviteUsers = (e) => {
this.authStore.settingsStore.setInvitePanelVisible(true);
};
onClickPin = (e, id, t) => {
@ -538,7 +538,7 @@ class ContextOptionsStore {
key: "invite-users-to-room",
label: "Invite users",
icon: "/static/images/person.react.svg",
onClick: () => this.onClickInviteUsers(),
onClick: (e) => this.onClickInviteUsers(e),
disabled: false,
},
{

View File

@ -248,6 +248,7 @@ class DialogsStore {
this.convertDialogVisible ||
this.selectFileDialogVisible ||
this.authStore.settingsStore.hotkeyPanelVisible ||
this.authStore.settingsStore.invitePanelVisible ||
this.versionHistoryStore.isVisible
);
}

View File

@ -128,6 +128,7 @@ class SettingsStore {
helpLink = null;
hotkeyPanelVisible = false;
frameConfig = null;
invitePanelVisible = false;
constructor() {
makeAutoObservable(this);
@ -548,6 +549,10 @@ class SettingsStore {
get isFrame() {
return this.frameConfig?.name === window.name;
}
setInvitePanelVisible = (invitePanelVisible) => {
this.invitePanelVisible = invitePanelVisible;
};
}
export default SettingsStore;