This commit is contained in:
mushka 2022-06-21 12:42:58 +03:00
parent d4cfd235fc
commit 343dd2174c
12 changed files with 1333 additions and 0 deletions

View File

@ -0,0 +1,143 @@
import styled, { css } from "styled-components";
import { Base } from "@appserver/components/themes";
import {
mobile,
smallTablet,
tablet,
} from "@appserver/components/utils/device";
const StyledHistoryList = styled.div`
display: flex;
flex-direction: column;
`;
const StyledUserNameLink = styled.span`
white-space: normal;
margin: 1px 0;
.username {
font-size: 13px;
font-weight: 600;
display: inline-block;
text-underline-offset: 2px;
}
`;
const StyledHistoryBlock = styled.div`
width: 100%;
display: flex;
gap: 8px;
padding: 16px 0;
border-bottom: ${(props) => `solid 1px ${props.theme.infoPanel.borderColor}`};
.avatar {
min-width: 32px;
}
.info {
width: calc(100% - 40px);
max-width: calc(100% - 40px);
display: flex;
flex-direction: column;
gap: 2px;
.title {
display: flex;
flex-direction: row;
gap: 4px;
.name {
font-weight: 600;
font-size: 14px;
color: #333333;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.secondary-info {
white-space: nowrap;
font-weight: 400;
font-size: 14px;
color: #a3a9ae;
@media ${mobile} {
display: none;
}
}
.date {
white-space: nowrap;
display: inline-block;
margin-left: auto;
font-weight: 600;
font-size: 12px;
color: #a3a9ae;
}
}
.block-content {
.appointing {
.appointing-user {
font-weight: 600;
font-size: 13px;
}
}
.users {
.user-list {
.space {
width: 4px;
display: inline-block;
}
}
}
.files-list {
margin-top: 10px;
display: flex;
flex-direction: column;
padding: 8px 0;
background: #f8f9f9;
border-radius: 3px;
.file {
padding: 4px 16px;
display: flex;
gap: 8px;
flex-direction: row;
align-items: center;
justify-content: start;
.icon {
min-width: 24px;
}
.file-title {
font-weight: 600;
font-size: 14px;
display: flex;
min-width: 0;
gap: 0;
.name {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.exst {
flex-shrink: 0;
color: #a3a9ae;
}
}
.location-btn {
margin-left: auto;
min-width: 16px;
}
}
}
}
}
`;
const StyledFileAction = styled.div``;
StyledHistoryBlock.defaultProps = { theme: Base };
export { StyledHistoryList, StyledUserNameLink, StyledHistoryBlock };

View File

@ -0,0 +1,68 @@
import styled, { css } from "styled-components";
import { Base } from "@appserver/components/themes";
const StyledUserTypeHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 24px 0 16px;
.title {
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-size: 13px;
line-height: 20px;
color: #a3a9ae;
}
.icon {
}
`;
const StyledUserList = styled.div`
display: flex;
flex-direction: column;
`;
const StyledUser = styled.div`
display: flex;
align-items: center;
gap: 8px;
padding: 8px 0;
.avatar {
min-width: 32px;
min-height: 32px;
}
.name {
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.secondary-info {
color: #a3a9ae;
}
}
.role {
margin-left: auto;
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-size: 13px;
line-height: 20px;
white-space: nowrap;
color: #555f65;
}
`;
export { StyledUserTypeHeader, StyledUserList, StyledUser };

View File

@ -0,0 +1,39 @@
import React from "react";
import styled from "styled-components";
import { withTranslation } from "react-i18next";
const EmptyScreenContainer = styled.div`
margin: 80px auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 32px;
.empty-screen-text {
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-size: 14px;
line-height: 16px;
text-align: center;
}
`;
const EmptyScreen = ({ t }) => {
return (
<EmptyScreenContainer>
<div className="no-thumbnail-img-wrapper">
<img
size="96px"
className="no-thumbnail-img"
src="images/empty_screen_info_panel.png"
/>
</div>
<div className="empty-screen-text">{t("EmptyScreenText")}</div>
</EmptyScreenContainer>
);
};
export default withTranslation(["InfoPanel"])(EmptyScreen);

View File

@ -0,0 +1,32 @@
import Text from "@appserver/components/text";
import React from "react";
import { withTranslation } from "react-i18next";
import { ReactSVG } from "react-svg";
import { StyledTitle } from "../../styles/styles.js";
const SeveralItems = (props) => {
const { t, selectedItems, getIcon, getFolderInfo } = props;
const itemsIcon = getIcon(24, ".file");
return (
<>
<StyledTitle>
<ReactSVG className="icon" src={itemsIcon} />
<Text className="text" fontWeight={600} fontSize="16px">
{`${t("ItemsSelected")}: ${selectedItems.length}`}
</Text>
</StyledTitle>
<div className="no-thumbnail-img-wrapper">
<img
size="96px"
className="no-thumbnail-img"
src="images/empty_screen.png"
/>
</div>
</>
);
};
export default withTranslation(["InfoPanel"])(SeveralItems);

View File

@ -0,0 +1,454 @@
import React, { useEffect, useState } from "react";
import { FileType } from "@appserver/common/constants";
import { LANGUAGE } from "@appserver/common/constants";
import Link from "@appserver/components/link";
import Text from "@appserver/components/text";
import Tooltip from "@appserver/components/tooltip";
import {
StyledAccess,
StyledAccessItem,
StyledOpenSharingPanel,
StyledProperties,
StyledSubtitle,
StyledThumbnail,
StyledTitle,
} from "../../styles/styles.js";
import getCorrectDate from "@appserver/components/utils/getCorrectDate";
const SingleItem = (props) => {
const {
t,
selectedItem,
onSelectItem,
setSharingPanelVisible,
//getFolderInfo,
getIcon,
getFolderIcon,
getShareUsers,
dontShowSize,
dontShowLocation,
dontShowAccess,
dontShowOwner,
personal,
createThumbnail,
culture,
} = props;
const [item, setItem] = useState({
id: "",
isFolder: false,
title: "",
iconUrl: "",
thumbnailUrl: "",
properties: [],
access: {
owner: {
img: "",
link: "",
},
others: [],
},
});
const updateItemsInfo = async (selectedItem) => {
const getItemIcon = (item, size) => {
return item.isFolder
? getFolderIcon(item.providerKey, size)
: getIcon(size, item.fileExst || ".file");
};
const getSingleItemProperties = (item) => {
const styledLink = (text, href) => (
<Link
isTextOverflow
className="property-content"
href={href}
isHovered={true}
>
{text}
</Link>
);
const styledText = (text) => (
<Text truncate className="property-content">
{text}
</Text>
);
const replaceUnicode = (str) => {
const regex = /&#([0-9]{1,4});/gi;
return str
? str.replace(regex, (match, numStr) => String.fromCharCode(+numStr))
: "...";
};
const parseAndFormatDate = (date) => {
const locale = personal ? localStorage.getItem(LANGUAGE) : culture;
const correctDate = getCorrectDate(locale, date);
return correctDate;
};
const getItemType = (fileType) => {
switch (fileType) {
case FileType.Unknown:
return t("Common:Unknown");
case FileType.Archive:
return t("Common:Archive");
case FileType.Video:
return t("Common:Video");
case FileType.Audio:
return t("Common:Audio");
case FileType.Image:
return t("Common:Image");
case FileType.Spreadsheet:
return t("Home:Spreadsheet");
case FileType.Presentation:
return t("Home:Presentation");
case FileType.Document:
return t("Home:Document");
default:
return t("Home:Folder");
}
};
const itemSize = item.isFolder
? `${t("Translations:Folders")}: ${item.foldersCount} | ${t(
"Translations:Files"
)}: ${item.filesCount}`
: item.contentLength;
const itemType = getItemType(item.fileType);
let result = [
{
id: "Owner",
title: t("Common:Owner"),
content: personal
? styledText(replaceUnicode(item.createdBy?.displayName))
: styledLink(
replaceUnicode(item.createdBy?.displayName),
item.createdBy?.profileUrl
),
},
// {
// id: "Location",
// title: t("InfoPanel:Location"),
// content: styledText("..."),
// },
{
id: "Type",
title: t("Common:Type"),
content: styledText(itemType),
},
{
id: "Size",
title: item.fileType ? t("Common:Size") : t("Common:Content"),
content: styledText(itemSize),
},
{
id: "ByLastModifiedDate",
title: t("Home:ByLastModifiedDate"),
content: styledText(parseAndFormatDate(item.updated)),
},
{
id: "LastModifiedBy",
title: t("LastModifiedBy"),
content: personal
? styledText(replaceUnicode(item.updatedBy?.displayName))
: styledLink(
replaceUnicode(item.updatedBy?.displayName),
item.updatedBy?.profileUrl
),
},
{
id: "ByCreationDate",
title: t("Home:ByCreationDate"),
content: styledText(parseAndFormatDate(item.created)),
},
];
if (dontShowOwner) result.shift();
if (item.isFolder) return result;
result.splice(3, 0, {
id: "FileExtension",
title: t("FileExtension"),
content: styledText(
item.fileExst ? item.fileExst.split(".")[1].toUpperCase() : "-"
),
});
result.push(
{
id: "Versions",
title: t("Versions"),
content: styledText(item.version),
},
{
id: "Comments",
title: t("Common:Comments"),
content: styledText(item.comment),
}
);
return result;
};
const displayedItem = {
id: selectedItem.id,
isFolder: selectedItem.isFolder,
title: selectedItem.title,
iconUrl: getItemIcon(selectedItem, 32),
thumbnailUrl: selectedItem.thumbnailUrl || getItemIcon(selectedItem, 96),
properties: getSingleItemProperties(selectedItem),
access: {
owner: {
img: selectedItem.createdBy?.avatarSmall,
link: selectedItem.createdBy?.profileUrl,
},
others: [],
},
};
setItem(displayedItem);
await loadAsyncData(displayedItem, selectedItem);
};
const loadAsyncData = async (displayedItem, selectedItem) => {
if (
!selectedItem.thumbnailUrl &&
!selectedItem.isFolder &&
selectedItem.thumbnailStatus === 0 &&
(selectedItem.fileType === FileType.Image ||
selectedItem.fileType === FileType.Spreadsheet ||
selectedItem.fileType === FileType.Presentation ||
selectedItem.fileType === FileType.Document)
) {
await createThumbnail(selectedItem.id);
}
// const updateLoadedItemProperties = async (displayedItem, selectedItem) => {
// const parentFolderId = selectedItem.isFolder
// ? selectedItem.parentId
// : selectedItem.folderId;
// const noLocationProperties = [...displayedItem.properties].filter(
// (dip) => dip.id !== "Location"
// );
// let result;
// await getFolderInfo(parentFolderId)
// .catch(() => {
// result = noLocationProperties;
// })
// .then((data) => {
// if (!data) {
// result = noLocationProperties;
// return;
// }
// result = [...displayedItem.properties].map((dip) =>
// dip.id === "Location"
// ? {
// id: "Location",
// title: t("Common:Location"),
// content: (
// <Link
// className="property-content"
// href={`/products/files/filter?folder=${parentFolderId}`}
// isHovered={true}
// >
// {data.title}
// </Link>
// ),
// }
// : dip
// );
// });
// return result;
// };
const updateLoadedItemAccess = async (selectedItem) => {
const accesses = await getShareUsers(
[selectedItem.isFolder ? selectedItem.parentId : selectedItem.folderId],
[selectedItem.id]
);
const result = {
owner: {},
others: [],
};
accesses.forEach((access) => {
let key = access.sharedTo.id,
img = access.sharedTo.avatarSmall,
link = access.sharedTo.profileUrl,
name = access.sharedTo.displayName || access.sharedTo.name,
{ manager } = access.sharedTo;
if (access.isOwner) result.owner = { key, img, link, name };
else {
if (access.sharedTo.email)
result.others.push({ key, type: "user", img, link, name });
else if (access.sharedTo.manager)
result.others.push({ key, type: "group", name, manager });
}
});
result.others = result.others.sort((a) => (a.type === "group" ? -1 : 1));
return result;
};
// const properties = await updateLoadedItemProperties(
// displayedItem,
// selectedItem
// );
if (dontShowAccess) {
setItem({
...displayedItem,
//properties: properties,
});
return;
}
if (!personal) {
const access = await updateLoadedItemAccess(selectedItem);
setItem({
...displayedItem,
// properties: properties,
access: access,
});
}
};
const openSharingPanel = () => {
const { id, isFolder } = item;
onSelectItem({ id, isFolder });
setSharingPanelVisible(true);
};
useEffect(() => {
updateItemsInfo(selectedItem);
}, [selectedItem]);
return (
<>
<StyledTitle>
<img className="icon" src={item.iconUrl} alt="thumbnail-icon" />
<Text className="text">{item.title}</Text>
</StyledTitle>
{selectedItem?.thumbnailUrl ? (
<StyledThumbnail>
<img
src={selectedItem.thumbnailUrl}
alt="thumbnail-image"
height={260}
width={360}
/>
</StyledThumbnail>
) : (
<div className="no-thumbnail-img-wrapper">
<img
className="no-thumbnail-img"
src={item.thumbnailUrl}
alt="thumbnail-icon-big"
/>
</div>
)}
<StyledSubtitle>
<Text fontWeight="600" fontSize="14px">
{t("SystemProperties")}
</Text>
</StyledSubtitle>
<StyledProperties>
{item.properties.map((p) => {
if (dontShowSize && p.id === "Size") return;
if (dontShowLocation && p.id === "Location") return;
return (
<div key={p.title} className="property">
<Text className="property-title">{p.title}</Text>
{p.content}
</div>
);
})}
</StyledProperties>
{!dontShowAccess && item.access && !personal && (
<>
<StyledSubtitle>
<Text fontWeight="600" fontSize="14px">
{t("WhoHasAccess")}
</Text>
</StyledSubtitle>
<StyledAccess>
<Tooltip
id="access-item-tooltip"
getContent={(dataTip) =>
dataTip ? <Text fontSize="13px">{dataTip}</Text> : null
}
/>
<StyledAccessItem>
<div
data-for="access-item-tooltip"
className="access-item-tooltip"
data-tip={item.access.owner.name}
>
<div className="item-user">
<a href={item.access.owner.link}>
<img src={item.access.owner.img} />
</a>
</div>
</div>
</StyledAccessItem>
{item.access.others.length > 0 && <div className="divider"></div>}
{item.access.others.map((item, i) => {
if (i < 3)
return (
<div key={item.key}>
<StyledAccessItem>
<div
data-for="access-item-tooltip"
data-tip={item.name}
className="access-item-tooltip"
>
{item.type === "user" ? (
<div className="item-user">
<a href={item.link}>
<img src={item.img} />
</a>
</div>
) : (
<div className="item-group">
<span>{item.name.substr(0, 2).toUpperCase()}</span>
</div>
)}
</div>
</StyledAccessItem>
</div>
);
})}
{item.access.others.length > 3 && (
<div className="show-more-users" onClick={openSharingPanel}>
{`+ ${item.access.others.length - 3} ${t("Members")}`}
</div>
)}
</StyledAccess>
<StyledOpenSharingPanel onClick={openSharingPanel}>
{t("OpenSharingSettings")}
</StyledOpenSharingPanel>
</>
)}
</>
);
};
export default SingleItem;

View File

@ -0,0 +1,88 @@
import React from "react";
import EmptyScreen from "./EmptyScreen";
import SeveralItems from "./SeveralItems";
import SingleItem from "./SingleItem";
const Details = ({
t,
selectedItems,
selectedFolder,
getFolderInfo,
getIcon,
getFolderIcon,
getShareUsers,
onSelectItem,
setSharingPanelVisible,
createThumbnail,
personal,
culture,
isRootFolder,
isRecycleBinFolder,
isRecentFolder,
isFavoritesFolder,
isShareFolder,
isCommonFolder,
isPrivacyFolder,
}) => {
const singleItem = (item) => {
const dontShowLocation = isRootFolder;
const dontShowSize = item.isFolder && (isFavoritesFolder || isRecentFolder);
const dontShowAccess =
isRecycleBinFolder ||
isRootFolder ||
item.rootFolderId === 7 ||
(item.isFolder && item.pathParts && item.pathParts[0] === 7);
const dontShowOwner = isRootFolder && (isFavoritesFolder || isRecentFolder);
return (
<SingleItem
t={t}
selectedItem={item}
onSelectItem={onSelectItem}
setSharingPanelVisible={setSharingPanelVisible}
getFolderInfo={getFolderInfo}
getIcon={getIcon}
getFolderIcon={getFolderIcon}
getShareUsers={getShareUsers}
dontShowLocation={dontShowLocation}
dontShowSize={dontShowSize}
dontShowAccess={dontShowAccess}
dontShowOwner={dontShowOwner}
personal={personal}
culture={culture}
createThumbnail={createThumbnail}
/>
);
};
return (
<>
{selectedItems.length === 0 ? (
// Can get future changes, currently only "My documents" displays its info
isRootFolder &&
(isRecycleBinFolder ||
isRecentFolder ||
isFavoritesFolder ||
isShareFolder ||
isCommonFolder) ? (
<EmptyScreen />
) : (
singleItem({
...selectedFolder,
isFolder: true,
})
)
) : selectedItems.length === 1 ? (
singleItem(selectedItems[0])
) : (
<SeveralItems selectedItems={selectedItems} getIcon={getIcon} />
)}
</>
);
};
export default Details;

View File

@ -0,0 +1,26 @@
import React from "react";
import styled from "styled-components";
import Text from "@appserver/components/text";
import { withTranslation } from "react-i18next";
const StyledGalleryEmptyScreen = styled.div`
.info-panel_gallery-empty-screen-img {
display: block;
margin: 0 auto;
padding: 56px 0 48px 0;
}
`;
const GalleryEmptyScreen = ({ t }) => {
return (
<StyledGalleryEmptyScreen className="info-panel_gallery-empty-screen">
<img
className="info-panel_gallery-empty-screen-img"
src="images/form-gallery-search.react.svg"
alt="Empty Screen Gallery image"
/>
<Text textAlign="center">{t("GalleryEmptyScreenDescription")}</Text>
</StyledGalleryEmptyScreen>
);
};
export default withTranslation("FormGallery")(GalleryEmptyScreen);

View File

@ -0,0 +1,101 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { withTranslation, Trans } from "react-i18next";
import { LANGUAGE } from "@appserver/common/constants";
import Text from "@appserver/components/text";
import { ReactSVG } from "react-svg";
import {
StyledProperties,
StyledSubtitle,
StyledGalleryThumbnail,
StyledTitle,
} from "../../styles/styles.js";
import getCorrectDate from "@appserver/components/utils/getCorrectDate";
const SingleItem = (props) => {
const { t, selectedItem, getIcon, culture, personal } = props;
const parseAndFormatDate = (date) => {
const locale = personal ? localStorage.getItem(LANGUAGE) : culture;
const correctDate = getCorrectDate(locale, date);
return correctDate;
};
const src = getIcon(32, ".docxf");
const thumbnailBlank = getIcon(96, ".docxf");
const thumbnailUrl =
selectedItem.attributes.template_image.data.attributes.formats.small.url;
return (
<>
<StyledTitle>
<ReactSVG className="icon" src={src} />
<Text className="text">{selectedItem.attributes.name_form}</Text>
</StyledTitle>
{thumbnailUrl ? (
<StyledGalleryThumbnail>
<img className="info-panel_gallery-img" src={thumbnailUrl} alt="" />
</StyledGalleryThumbnail>
) : (
<div className="no-thumbnail-img-wrapper">
<ReactSVG className="no-thumbnail-img" src={thumbnailBlank} />
</div>
)}
<StyledSubtitle>
<Text fontWeight="600" fontSize="14px">
{t("SystemProperties")}
</Text>
</StyledSubtitle>
<StyledProperties>
<div className="property">
<Text className="property-title">{t("Home:ByLastModifiedDate")}</Text>
<Text className="property-content">
{parseAndFormatDate(selectedItem.attributes.updatedAt)}
</Text>
</div>
<div className="property">
<Text className="property-title">{t("Common:Size")}</Text>
<Text className="property-content">
{selectedItem.attributes.file_size}
</Text>
</div>
<div className="property">
<Text className="property-title">{t("Common:Pages")}</Text>
<Text className="property-content">
{selectedItem.attributes.file_pages}
</Text>
</div>
<Text
as="div"
fontSize="12px"
fontWeight={400}
className="oforms-description"
>
<Trans t={t} i18nKey="OFORMsDescription" ns="InfoPanel">
Fill out the form online and get a simple Design Project Proposal
ready, or just download the fillable template in the desirable
format: DOCXF, OFORM, or PDF.
<p className="oforms-description-text">
Propose a project or a series of projects to an freelance designer
team. Outline project and task structure, payments, and terms.
</p>
</Trans>
</Text>
</StyledProperties>
</>
);
};
export default inject(({ settingsStore }) => {
const { getIcon, personal, culture } = settingsStore;
return {
getIcon,
};
})(withTranslation(["InfoPanel", "Common", "Home"])(observer(SingleItem)));

View File

@ -0,0 +1,87 @@
import React from "react";
import Text from "@appserver/components/text";
import Link from "@appserver/components/link";
import IconButton from "@appserver/components/icon-button";
import { ReactSVG } from "react-svg";
import { StyledUserNameLink } from "../../styles/VirtualRoom/history";
const HistoryBlockContent = ({ t, action, details }) => {
return (
<div className="block-content">
{action === "message" ? (
<Text>{details.message}</Text>
) : action === "appointing" ? (
<div className="appointing">
{`${t("appointed")}
${details.appointedRole} `}{" "}
<UserNameLink user={details.appointedUser} />
</div>
) : action === "users" ? (
<div className="users">
<div className="user-list">
added users{" "}
{details.users.map((user, i) => (
<UserNameLink
key={user.id}
user={user}
withComma={i + 1 !== details.users.length}
/>
))}
</div>
</div>
) : action === "files" ? (
<div className="files">
<Text>add new 2 files into the folder My project</Text>
<div className="files-list">
{details.files.map((file) => (
<div className="file" key={file.id}>
<ReactSVG className="icon" src={file.icon} />
<div className="file-title">
<span className="name">{file.title.split(".")[0]}</span>
<span className="exst">{file.fileExst}</span>
</div>
<IconButton
className="location-btn"
iconName="/static/images/folder-location.react.svg"
size="16"
isFill={true}
onClick={() => {}}
/>
</div>
))}
</div>
</div>
) : null}
</div>
);
};
const UserNameLink = ({ user, withComma }) => {
const username = user.displayName || user.email;
const space = <div className="space"></div>;
return (
<StyledUserNameLink className="user">
{user.profileUrl ? (
<Link
className="username link"
isHovered
type="action"
href={user.profileURl}
>
{username}
{withComma ? "," : ""}
{withComma && space}
</Link>
) : (
<div className="username text" key={user.id}>
{username}
{withComma ? "," : ""}
{withComma && space}
</div>
)}
</StyledUserNameLink>
);
};
export default HistoryBlockContent;

View File

@ -0,0 +1,72 @@
import Avatar from "@appserver/components/avatar";
import ContextMenuButton from "@appserver/components/context-menu-button";
import Text from "@appserver/components/text";
import React from "react";
import { StyledTitle } from "../../styles/styles";
import {
StyledHistoryBlock,
StyledHistoryList,
} from "../../styles/VirtualRoom/history";
import { fillingFormsVR } from "../mock_data";
import getCorrectDate from "@appserver/components/utils/getCorrectDate";
import HistoryBlockContent from "./historyBlockContent";
const History = ({ t, personal, culture }) => {
const data = fillingFormsVR;
const parseAndFormatDate = (date) => {
const locale = personal ? localStorage.getItem(LANGUAGE) : culture;
const correctDate = getCorrectDate(locale, date);
return correctDate;
};
return (
<>
<StyledTitle withBottomBorder>
<img className="icon" src={data.icon} alt="thumbnail-icon" />
<Text className="text">{data.title}</Text>
<ContextMenuButton getData={() => {}} className="context-menu-button" />
</StyledTitle>
<StyledHistoryList>
{data.history.map((operation) => (
<StyledHistoryBlock key={operation.id}>
<Avatar
role="user"
className="avatar"
size="min"
source={
operation.user.avatar ||
(operation.user.displayName
? ""
: operation.user.email && "/static/images/@.react.svg")
}
userName={operation.user.displayName}
/>
<div className="info">
<div className="title">
<Text className="name">{operation.user.displayName}</Text>
{operation.user.isOwner && (
<Text className="secondary-info">
{t("Common:Owner").toLowerCase()}
</Text>
)}
<Text className="date">
{parseAndFormatDate(operation.date)}
</Text>
</div>
<HistoryBlockContent
t={t}
action={operation.action}
details={operation.details}
/>
</div>
</StyledHistoryBlock>
))}
</StyledHistoryList>
</>
);
};
export default History;

View File

@ -0,0 +1,105 @@
import Avatar from "@appserver/components/avatar";
import ContextMenuButton from "@appserver/components/context-menu-button";
import IconButton from "@appserver/components/icon-button";
import Text from "@appserver/components/text";
import React from "react";
import { StyledTitle } from "../../styles/styles";
import {
StyledUser,
StyledUserList,
StyledUserTypeHeader,
} from "../../styles/VirtualRoom/members";
import { fillingFormsVR } from "../mock_data";
const Members = ({ t, selfId }) => {
const data = fillingFormsVR;
return (
<>
<StyledTitle withBottomBorder>
<img className="icon" src={data.icon} alt="thumbnail-icon" />
<Text className="text">{data.title}</Text>
<ContextMenuButton getData={() => {}} className="context-menu-button" />
</StyledTitle>
<StyledUserTypeHeader>
<Text className="title">
{t("Users in room")} : {data.members.inRoom.length}
</Text>
<IconButton
title={t("Common:AddUsers")}
iconName="/static/images/person+.react.svg"
isFill={true}
onClick={() => {}}
size={16}
color={"#316DAA"}
/>
</StyledUserTypeHeader>
<StyledUserList>
{data.members.inRoom.map((user) => (
<StyledUser key={user.id} canEdit>
<Avatar
role="user"
className="avatar"
size="min"
source={
user.avatar ||
(user.displayName
? ""
: user.email && "/static/images/@.react.svg")
}
userName={user.displayName}
/>
<div className="name">
{user.displayName || user.email}
{selfId === user.id && (
<span className="secondary-info">
{" (" + t("Common:MeLabel") + ")"}
</span>
)}
</div>
</StyledUser>
))}
</StyledUserList>
<StyledUserTypeHeader>
<Text className="title">
{t("Expect people")} : {data.members.expect.length}
</Text>
<IconButton
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={() => {}}
size={16}
color={"#316DAA"}
/>
</StyledUserTypeHeader>
<StyledUserList>
{data.members.expect.map((user) => (
<StyledUser key={user.id} canEdit>
<Avatar
role="user"
className="avatar"
size="min"
source={
user.avatar ||
(user.displayName
? ""
: user.email && "/static/images/@.react.svg")
}
userName={user.displayName}
/>
<Text truncate className="name">
{user.displayName || user.email}
</Text>
</StyledUser>
))}
</StyledUserList>
</>
);
};
export default Members;

View File

@ -0,0 +1,118 @@
const files = [
{
fileExst: ".png",
icon: "/static/images/icons/24/image.svg",
isFolder: false,
id: 34,
title: "Windows 12 Wallpaper Purple.png",
},
{
fileExst: ".pptx",
icon: "/static/images/icons/24/pptx.svg",
isFolder: false,
id: 3,
title: "ONLYOFFICE Sample Presentation With Long Name.pptx",
},
{
fileExst: ".docx",
icon: "/static/images/icons/24/docx.svg",
isFolder: false,
id: 5,
title: "курсач.docx",
},
];
const people = [
{
email: "nikita.mushka@onlyoffice.com",
avatar:
"/storage/userPhotos/root/2af62a34-b6c8-11ec-b1d9-b42e99bd46a3_size_82-82.jpeg?_=1354477264",
isOwner: true,
id: "2af62a34-b6c8-11ec-b1d9-b42e99bd46a3",
displayName: "Мушка Никита",
profileUrl: "http://localhost:8092/products/people/view/administrator",
},
{
email: "yoshiko05@rohan.biz",
avatar: "",
isOwner: false,
id: "1231234",
displayName: "Rebecca Holt",
profileUrl: "asdasd",
},
{
email: "yoshiko05@rohan.biz",
avatar:
"https://images.unsplash.com/photo-1519699047748-de8e457a634e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80",
isOwner: false,
id: "345970",
displayName: "Angela Garcia",
profileUrl: "",
},
{
email: "kk@mail.ru",
avatar: "/images/default_user_photo_size_82-82.png",
isOwner: false,
id: "5db1213e-7f73-434e-9d6a-af699821d3c9",
displayName:
"Some random guy with a really long name, like i mean some dumb long one",
profileUrl: "http://localhost:8092/products/people/view/kk",
},
{
email: "ycummerata@yahoo.com",
avatar: "",
isOwner: false,
id: "389457",
displayName: "",
profileUrl: "",
},
];
const fillingFormsVR = {
title: "Filling forms room",
icon: "images/icons/32/folder.svg",
members: {
inRoom: [...people.slice(0, 3)],
expect: [...people.slice(3)],
},
history: [
{
id: 3,
user: people[0],
date: "2022-04-23T19:04:43.511Z",
action: "files",
details: { type: "delete", files: [...files] },
},
{
id: 2,
user: people[0],
date: "2022-04-23T18:39:43.511Z",
action: "appointing",
details: {
appointedUser: people[1],
appointedRole: "room administrator",
},
},
{
id: 1,
user: people[0],
date: "2022-04-23T18:35:43.511Z",
action: "users",
details: {
type: "add",
users: [...people.slice(1)],
},
},
{
id: 0,
user: people[0],
date: "2022-04-23T18:25:43.511Z",
action: "message",
details: { message: 'Created room "Filling forms room"' },
},
],
};
export { fillingFormsVR };