added user sessions panel

This commit is contained in:
Elyor Djalilov 2024-01-31 18:21:20 +05:00
parent b115f7f264
commit d96bf657e0
13 changed files with 479 additions and 158 deletions

View File

@ -0,0 +1,47 @@
import { Text } from "@docspace/shared/components/text";
import { Button } from "@docspace/shared/components/button";
import styled from "styled-components";
import RowWrapper from "./sub-components";
const Wrapper = styled.div`
padding: 20px 20px 12px;
.subtitle {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.desciption {
color: #657077;
margin-bottom: 20px;
}
`;
const AllSessionsBlock = (props) => {
const { t, allSessions } = props;
const onLogoutClick = () => {
console.log("Logout all sessions");
};
return (
<>
<Wrapper>
<Text className="subtitle">{t("Profile:AllSessions")}</Text>
<Text className="desciption">{t("Profile:PanelDescription")}</Text>
<Button
label={t("Profile:LogoutFromAllSessions")}
size="small"
onClick={onLogoutClick}
scale={true}
isLoading={false}
/>
</Wrapper>
<RowWrapper t={t} sessionsData={allSessions} />
</>
);
};
export default AllSessionsBlock;

View File

@ -0,0 +1,72 @@
import styled from "styled-components";
import { Box } from "@docspace/shared/components/box";
import { Text } from "@docspace/shared/components/text";
const StyledLastSessionBlock = styled.div`
padding: 0px 20px;
.subtitle {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.online {
color: #35ad17;
}
.session-info-wrapper {
display: flex;
align-items: center;
.session-info-left-container {
margin-right: 24px;
p {
padding-left: 0px;
padding: 8px;
font-size: 13px;
}
}
.session-info-right-container {
p {
font-weight: 600;
padding: 8px;
font-size: 13px;
}
}
}
`;
const LastSessionBlock = (props) => {
const { t, data } = props;
const { status, platform, browser, ip, country, city } = data;
const isOnline = status === "Online";
return (
<StyledLastSessionBlock>
<Text className="subtitle">{t("Profile:LastSession")}</Text>
<Box className="session-info-wrapper">
<div className="session-info-left-container">
<Text>{t("Common:Active")}</Text>
<Text>{t("Common:Platform")}</Text>
<Text>{t("Common:Browser")}</Text>
<Text>{t("Common:IpAddress")}</Text>
<Text>{t("Common:Country")}</Text>
<Text>{t("Common:City")}</Text>
</div>
<div className="session-info-right-container">
<Text className={isOnline && "online"}>{status}</Text>
<Text>{platform}</Text>
<Text>{browser}</Text>
<Text>{ip}</Text>
<Text>{country}</Text>
<Text>{city}</Text>
</div>
</Box>
</StyledLastSessionBlock>
);
};
export default LastSessionBlock;

View File

@ -1,32 +0,0 @@
import styled from "styled-components";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
import { Base } from "@docspace/shared/themes";
const StyledUserSessionsPanel = styled.div`
.user-sessions-panel {
.scroll-body {
padding-right: 0px !important;
}
}
.user-sessions-header {
padding: 0px 16px;
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
.header-text {
font-weight: 700;
font-size: 21px;
margin: 12px 0px;
}
}
`;
const StyledScrollbar = styled(Scrollbar)`
position: relative;
padding: 16px 0;
height: calc(100vh - 87px) !important;
`;
StyledUserSessionsPanel.defaultProps = { theme: Base };
export { StyledUserSessionsPanel, StyledScrollbar };

View File

@ -0,0 +1,94 @@
import { Avatar } from "@docspace/shared/components/avatar";
import { Box } from "@docspace/shared/components/box";
import { Text } from "@docspace/shared/components/text";
import { ContextMenuButton } from "@docspace/shared/components/context-menu-button";
import styled from "styled-components";
import LogoutReactSvgUrl from "PUBLIC_DIR/images/logout.react.svg?url";
import RemoveSvgUrl from "PUBLIC_DIR/images/remove.session.svg?url";
const StyledUserInfoBlock = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 24px 20px 20px;
.username {
font-size: 16px;
font-weight: 700;
}
span {
font-size: 13px;
color: #a3a9ae;
font-weight: 600;
}
.avatar {
margin-right: 16px;
}
`;
const UserInfoBlock = (props) => {
const {
t,
data,
setLogoutAllDialogVisible,
setDisableDialogVisible,
setSessionModalData,
} = props;
const { avatar, role, displayName, userType } = data;
const onClickLogout = () => {
setLogoutAllDialogVisible(true);
setSessionModalData({ ...data, displayName });
};
const onClickDisable = () => {
setDisableDialogVisible(true);
};
const contextOptions = () => {
return [
{
key: "LogoutAllSessions",
label: t("Settings:LogoutAllSessions"),
icon: LogoutReactSvgUrl,
onClick: onClickLogout,
},
{
key: "Separator",
isSeparator: true,
},
{
key: "Disable",
label: t("Common:DisableUserButton"),
icon: RemoveSvgUrl,
onClick: onClickDisable,
},
];
};
return (
<StyledUserInfoBlock>
<Box displayProp="flex" alignItems="center" justifyContent="center">
<Avatar
className="avatar"
role={role}
size="big"
userName={displayName}
source={avatar}
/>
<Box displayProp="flex" flexDirection="column">
<Text className="username">{displayName}</Text>
<span>{userType}</span>
</Box>
</Box>
<ContextMenuButton getData={contextOptions} />
</StyledUserInfoBlock>
);
};
export default UserInfoBlock;

View File

@ -1,108 +0,0 @@
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { isMobile } from "react-device-detect";
import { Base } from "@docspace/shared/themes";
import { tablet } from "@docspace/shared/utils";
import { Row } from "@docspace/shared/components/row";
import { Avatar } from "@docspace/shared/components/avatar";
import styled, { css } from "styled-components";
import RemoveSvgUrl from "PUBLIC_DIR/images/remove.session.svg?url";
import TrashReactSvgUrl from "PUBLIC_DIR/images/trash.react.svg?url";
const marginStyles = css`
margin-left: -24px;
margin-right: -24px;
padding-left: 24px;
padding-right: 24px;
@media ${tablet} {
margin-left: -16px;
margin-right: -16px;
padding-left: 16px;
padding-right: 16px;
}
`;
const checkedStyle = css`
background: ${(props) => props.theme.filesSection.rowView.checkedBackground};
${marginStyles}
`;
const Wrapper = styled.div`
padding: 24px 20px;
`;
const UserSessions = (props) => {
const {
t,
data,
setLogoutAllDialogVisible,
setDisableDialogVisible,
setSessionModalData,
} = props;
const contextOptions = [
{
key: "LogoutAllSessions",
label: t("Settings:LogoutAllSessions"),
icon: RemoveSvgUrl,
onClick: onClickLogout,
},
{
key: "Separator",
isSeparator: true,
},
{
key: "Disable",
label: t("Common:DisableUserButton"),
icon: TrashReactSvgUrl,
onClick: onClickDisable,
},
];
const onClickLogout = () => {
setLogoutAllDialogVisible(true);
setSessionModalData({ displayName: data.displayName });
};
const onClickDisable = () => {
setDisableDialogVisible(true);
};
console.log(data);
const element = (
<Avatar size="large" userName={data.displayName} source={data.avatar} />
);
return (
<Wrapper>
<Row
key={data.userId}
data={data}
element={element}
mode={"modern"}
className={"user-row"}
withoutBorder
contextOptions={contextOptions}
/>
</Wrapper>
);
};
export default inject(({ setup }) => {
const {
setLogoutAllDialogVisible,
setDisableDialogVisible,
setSessionModalData,
sessionModalData,
} = setup;
return {
setLogoutAllDialogVisible,
setDisableDialogVisible,
setSessionModalData,
data: sessionModalData,
};
})(withTranslation(["Settings", "Profile", "Common"])(observer(UserSessions)));

View File

@ -1,20 +1,44 @@
import { useRef } from "react"; import { useRef } from "react";
import { withTranslation } from "react-i18next";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import styled from "styled-components";
import { Backdrop } from "@docspace/shared/components/backdrop"; import { Backdrop } from "@docspace/shared/components/backdrop";
import { Aside } from "@docspace/shared/components/aside"; import { Aside } from "@docspace/shared/components/aside";
import { Heading } from "@docspace/shared/components/heading"; import { Heading } from "@docspace/shared/components/heading";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
import UserSessions from "./UserSessions"; import AllSessionsBlock from "./AllSessionsBlock";
import LastSessionBlock from "./LastSessionBlock";
import UserInfoBlock from "./UserInfoBlock";
import { const StyledSessionsPanel = styled.div`
StyledUserSessionsPanel, .user-sessions-panel {
StyledScrollbar, .scroll-body {
} from "./StyledUserSessionsPanel"; padding-right: 0px !important;
}
}
`;
const StyledHeaderContent = styled.div`
padding: 0px 16px;
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
.user-sessions-panel-heading {
font-weight: 700;
font-size: 21px;
margin: 12px 0px;
}
`;
const StyledScrollbar = styled(Scrollbar)`
position: relative;
padding: 16px 0;
height: calc(100vh - 87px) !important;
`;
const UserSessionsPanel = (props) => { const UserSessionsPanel = (props) => {
const { visible, setVisible } = props; const { t, visible, setVisible } = props;
const scrollRef = useRef(null); const scrollRef = useRef(null);
const onClose = () => { const onClose = () => {
@ -22,7 +46,7 @@ const UserSessionsPanel = (props) => {
}; };
return ( return (
<StyledUserSessionsPanel> <StyledSessionsPanel>
<Backdrop <Backdrop
onClick={onClose} onClick={onClose}
visible={visible} visible={visible}
@ -34,23 +58,43 @@ const UserSessionsPanel = (props) => {
visible={visible} visible={visible}
onClose={onClose} onClose={onClose}
> >
<div className="user-sessions-header"> <StyledHeaderContent>
<Heading className="header-text">Active sessions</Heading> <Heading className="user-sessions-panel-heading">
</div> {t("Profile:ActiveSessions")}
</Heading>
</StyledHeaderContent>
<StyledScrollbar ref={scrollRef} stype="mediumBlack"> <StyledScrollbar ref={scrollRef}>
<UserSessions /> <UserInfoBlock {...props} />
<LastSessionBlock {...props} />
<AllSessionsBlock {...props} />
</StyledScrollbar> </StyledScrollbar>
</Aside> </Aside>
</StyledUserSessionsPanel> </StyledSessionsPanel>
); );
}; };
export default inject(({ dialogsStore }) => { export default inject(({ setup, peopleStore, dialogsStore }) => {
const { allSessions } = peopleStore.selectionStore;
const { userSessionsPanelVisible, setUserSessionPanelVisible } = dialogsStore; const { userSessionsPanelVisible, setUserSessionPanelVisible } = dialogsStore;
const {
setLogoutAllDialogVisible,
setDisableDialogVisible,
sessionModalData,
setSessionModalData,
} = setup;
return { return {
allSessions,
data: sessionModalData,
setSessionModalData,
setLogoutAllDialogVisible,
setDisableDialogVisible,
visible: userSessionsPanelVisible, visible: userSessionsPanelVisible,
setVisible: setUserSessionPanelVisible, setVisible: setUserSessionPanelVisible,
}; };
})(observer(UserSessionsPanel)); })(
withTranslation(["Settings", "Profile", "Common"])(
observer(UserSessionsPanel)
)
);

View File

@ -0,0 +1,33 @@
import { inject, observer } from "mobx-react";
import { Row } from "@docspace/shared/components/row";
import styled from "styled-components";
import SessionsRowContent from "./SessionsRowContent";
const StyledRow = styled(Row)`
min-height: 56px;
`;
const SessionsRow = (props) => {
const { item, sectionWidth } = props;
return (
<StyledRow
key={item.userId}
data={item}
sectionWidth={sectionWidth}
contextButtonSpacerWidth="0"
>
<SessionsRowContent {...props} />
</StyledRow>
);
};
export default inject(({ setup }) => {
const { setSessionModalData, setLogoutDialogVisible } = setup;
return {
setSessionModalData,
setLogoutDialogVisible,
};
})(observer(SessionsRow));

View File

@ -0,0 +1,118 @@
import { Text } from "@docspace/shared/components/text";
import { Box } from "@docspace/shared/components/box";
import { convertTime } from "@docspace/shared/utils/convertTime";
import { RowContent } from "@docspace/shared/components/row-content";
import { ReactSVG } from "react-svg";
import RemoveSessionSvgUrl from "PUBLIC_DIR/images/remove.session.svg?url";
import styled from "styled-components";
const StyledRowContent = styled(RowContent)`
.rowMainContainer {
height: 100%;
width: 100%;
margin-right: 0px;
}
.row-main-container-wrapper {
width: 100%;
}
.session-info-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
}
.session-logout-icon {
cursor: pointer;
margin-left: 5px;
}
.session-content-wrapper {
width: 100%;
min-width: 150px;
}
.main-row-content {
display: flex;
align-items: center;
.platform,
.browser {
font-size: 14px;
color: #333;
font-weight: 600;
margin-right: 5px;
}
.date {
font-size: 14px;
font-weight: 600;
color: #a3a9ae;
}
}
.additional-row-content {
display: flex;
align-items: center;
.country,
.city {
font-size: 12px;
font-weight: 600;
color: #a3a9ae;
}
.city {
margin-left: 5px;
}
}
`;
const SessionsRowContent = ({
item,
sectionWidth,
setSessionModalData,
setLogoutDialogVisible,
}) => {
const { date, platform, browser, country, city, userId } = item;
const onClickDisable = () => {
setLogoutDialogVisible(true);
setSessionModalData({
...item,
platform: item.platform,
broser: item.browser,
});
};
const contentData = [
<Box key={userId} className="session-info-wrapper">
<Box className="session-content-wrapper">
<Box className="main-row-content">
<Text className="platform">{platform},</Text>
<Text className="browser">{browser}</Text>
<Text className="date" truncate>
{convertTime(date)}
</Text>
</Box>
<Box className="additional-row-content">
<Text className="country">{country},</Text>
<Text className="city">{city}</Text>
</Box>
</Box>
<Box className="session-logout-icon">
<ReactSVG src={RemoveSessionSvgUrl} onClick={onClickDisable} />
</Box>
</Box>,
];
return (
<StyledRowContent sectionWidth={sectionWidth}>
{contentData}
</StyledRowContent>
);
};
export default SessionsRowContent;

View File

@ -0,0 +1,33 @@
import { RowContainer } from "@docspace/shared/components/row-container";
import styled from "styled-components";
import SessionsRow from "./SessionsRow";
const StyledRowContainer = styled(RowContainer)`
padding: 0px 16px;
`;
const RowView = (props) => {
const { t, sectionWidth, sessionsData } = props;
return (
<StyledRowContainer
useReactWindow={false}
hasMoreFiles={false}
itemHeight={58}
itemCount={sessionsData.length}
filesLength={sessionsData.length}
fetchMoreFiles={() => {}}
>
{sessionsData.map((item) => (
<SessionsRow
t={t}
key={item.id}
item={item}
sectionWidth={sectionWidth}
/>
))}
</StyledRowContainer>
);
};
export default RowView;

View File

@ -0,0 +1,18 @@
import { Consumer } from "@docspace/shared/utils";
import RowView from "./RowView";
const RowWrapper = ({ t, sessionsData }) => {
return (
<Consumer>
{(context) => (
<RowView
t={t}
sectionWidth={context.sectionWidth}
sessionsData={sessionsData}
/>
)}
</Consumer>
);
};
export default RowWrapper;

View File

@ -346,12 +346,13 @@ const SectionHeaderContent = (props) => {
); );
const onClickSessions = () => { const onClickSessions = () => {
setSessionModalData({ ...peopleSelection[0] });
setUserSessionPanelVisible(true); setUserSessionPanelVisible(true);
}; };
const onClickLogout = () => { const onClickLogout = () => {
setLogoutAllDialogVisible(true);
setSessionModalData({ displayName: peopleSelection[0].displayName }); setSessionModalData({ displayName: peopleSelection[0].displayName });
setLogoutAllDialogVisible(true);
}; };
const onClickDisable = () => { const onClickDisable = () => {

View File

@ -123,7 +123,7 @@ const SessionsRow = (props) => {
}, [isChecked, item, onContentRowClick]); }, [isChecked, item, onContentRowClick]);
const onClickSessions = () => { const onClickSessions = () => {
console.log("view sessions"); setSessionModalData({ ...item });
}; };
const onClickLogout = () => { const onClickLogout = () => {

View File

@ -152,6 +152,7 @@ const SessionsTableRow = (props) => {
} = props; } = props;
const onClickSessions = () => { const onClickSessions = () => {
setSessionModalData({ ...item });
setUserSessionPanelVisible(true); setUserSessionPanelVisible(true);
}; };