Web: Client: Added base invite panel
This commit is contained in:
parent
e2472b392e
commit
4092aa546a
@ -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));
|
||||
|
@ -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;
|
@ -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,
|
||||
};
|
127
packages/client/src/components/panels/InvitePanel/index.js
Normal file
127
packages/client/src/components/panels/InvitePanel/index.js
Normal 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))
|
||||
);
|
78
packages/client/src/components/panels/InvitePanel/items.js
Normal file
78
packages/client/src/components/panels/InvitePanel/items.js
Normal 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;
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
@ -248,6 +248,7 @@ class DialogsStore {
|
||||
this.convertDialogVisible ||
|
||||
this.selectFileDialogVisible ||
|
||||
this.authStore.settingsStore.hotkeyPanelVisible ||
|
||||
this.authStore.settingsStore.invitePanelVisible ||
|
||||
this.versionHistoryStore.isVisible
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user