files
This commit is contained in:
parent
d4cfd235fc
commit
343dd2174c
@ -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 };
|
@ -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 };
|
@ -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);
|
@ -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);
|
@ -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;
|
@ -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;
|
@ -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);
|
@ -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)));
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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 };
|
Loading…
Reference in New Issue
Block a user