Merge branch 'develop' into feature/list-accounts-additional-info
This commit is contained in:
commit
e4339f721f
63
packages/client/src/components/TariffBar/helpers.js
Normal file
63
packages/client/src/components/TariffBar/helpers.js
Normal file
@ -0,0 +1,63 @@
|
||||
const ORANGE = "#F97A0B";
|
||||
const RED = "#F2665A";
|
||||
|
||||
export const getSaasBar = (
|
||||
t,
|
||||
isPaymentPageAvailable,
|
||||
isNonProfit,
|
||||
isFreeTariff,
|
||||
isGracePeriod
|
||||
) => {
|
||||
if (
|
||||
isPaymentPageAvailable &&
|
||||
!isNonProfit &&
|
||||
(isFreeTariff || isGracePeriod)
|
||||
) {
|
||||
if (isFreeTariff) return { label: t("Common:TryBusiness"), color: ORANGE };
|
||||
if (isGracePeriod) return { label: t("Common:LatePayment"), color: RED };
|
||||
}
|
||||
};
|
||||
|
||||
export const getEnterpriseBar = (
|
||||
t,
|
||||
isPaymentPageAvailable,
|
||||
isEnterprise,
|
||||
isTrial,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
trialDaysLeft,
|
||||
paymentDate
|
||||
) => {
|
||||
if (
|
||||
isPaymentPageAvailable &&
|
||||
isEnterprise &&
|
||||
(isTrial || isLicenseExpiring || isLicenseDateExpired)
|
||||
) {
|
||||
if (isTrial) {
|
||||
if (isLicenseDateExpired)
|
||||
return { label: t("Common:TrialExpired"), color: ORANGE };
|
||||
return {
|
||||
label: t("Common:TrialDaysLeft", { count: trialDaysLeft }),
|
||||
color: ORANGE,
|
||||
};
|
||||
} else {
|
||||
if (isLicenseDateExpired)
|
||||
return {
|
||||
label: t("Common:SubscriptionExpiredTitle"),
|
||||
color: RED,
|
||||
};
|
||||
return {
|
||||
label: t("Common:SubscriptionIsExpiring", { date: paymentDate }),
|
||||
color: ORANGE,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const checkBar = () => {
|
||||
const el = document.getElementById("tariff-bar-text");
|
||||
el?.classList?.remove("hidden");
|
||||
if (el?.offsetWidth < el?.scrollWidth) {
|
||||
el?.classList?.add("hidden");
|
||||
}
|
||||
};
|
135
packages/client/src/components/TariffBar/index.js
Normal file
135
packages/client/src/components/TariffBar/index.js
Normal file
@ -0,0 +1,135 @@
|
||||
import { useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { getSaasBar, getEnterpriseBar, checkBar } from "./helpers";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
display: grid;
|
||||
cursor: pointer;
|
||||
|
||||
#tariff-bar-text:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
#tariff-bar-text:active {
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
`;
|
||||
|
||||
const PROXY_BASE_URL = combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
"/portal-settings"
|
||||
);
|
||||
|
||||
const TariffBar = ({
|
||||
isEnterprise,
|
||||
isNonProfit,
|
||||
isGracePeriod,
|
||||
isFreeTariff,
|
||||
isPaymentPageAvailable,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
isTrial,
|
||||
standalone,
|
||||
paymentDate,
|
||||
trialDaysLeft,
|
||||
title,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation("Common");
|
||||
|
||||
const onClick = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
PROXY_BASE_URL,
|
||||
"/payments/portal-payments"
|
||||
);
|
||||
navigate(paymentPageUrl);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkBar();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
checkBar();
|
||||
}, [title]);
|
||||
|
||||
const tariffBar = !standalone
|
||||
? getSaasBar(
|
||||
t,
|
||||
isPaymentPageAvailable,
|
||||
isNonProfit,
|
||||
isFreeTariff,
|
||||
isGracePeriod
|
||||
)
|
||||
: getEnterpriseBar(
|
||||
t,
|
||||
isPaymentPageAvailable,
|
||||
isEnterprise,
|
||||
isTrial,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
trialDaysLeft,
|
||||
paymentDate
|
||||
);
|
||||
|
||||
if (!tariffBar) return <></>;
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Text
|
||||
id="tariff-bar-text"
|
||||
as="div"
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
lineHeight="16px"
|
||||
color={tariffBar.color}
|
||||
onClick={onClick}
|
||||
truncate={true}
|
||||
>
|
||||
{tariffBar.label}
|
||||
</Text>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
const {
|
||||
settingsStore,
|
||||
currentQuotaStore,
|
||||
isPaymentPageAvailable,
|
||||
currentTariffStatusStore,
|
||||
isEnterprise,
|
||||
} = auth;
|
||||
const { isFreeTariff, isNonProfit, isTrial } = currentQuotaStore;
|
||||
const {
|
||||
isGracePeriod,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
paymentDate,
|
||||
trialDaysLeft,
|
||||
} = currentTariffStatusStore;
|
||||
const { standalone } = settingsStore;
|
||||
|
||||
return {
|
||||
isEnterprise,
|
||||
isNonProfit,
|
||||
isGracePeriod,
|
||||
isFreeTariff,
|
||||
isPaymentPageAvailable,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
isTrial,
|
||||
standalone,
|
||||
paymentDate,
|
||||
trialDaysLeft,
|
||||
};
|
||||
})(observer(TariffBar));
|
@ -22,6 +22,11 @@ class TagHandler {
|
||||
|
||||
addTag(name) {
|
||||
let newTags = [...this.tags];
|
||||
|
||||
if (this.isAlreadyAdded(name)) {
|
||||
return; //already added
|
||||
}
|
||||
|
||||
newTags.push({
|
||||
id: this.createRandomTagId(),
|
||||
name,
|
||||
@ -29,11 +34,26 @@ class TagHandler {
|
||||
this.setTags(newTags);
|
||||
}
|
||||
|
||||
isAlreadyAdded(name) {
|
||||
return !!this.tags.find((t) => t.name.toLowerCase() === name.toLowerCase());
|
||||
}
|
||||
|
||||
isNew(name) {
|
||||
return !this.fetchedTags.find(
|
||||
(t) => t.toLowerCase() === name.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
addNewTag(name) {
|
||||
let newTags = [...this.tags];
|
||||
|
||||
if (this.isAlreadyAdded(name)) {
|
||||
return; //already added
|
||||
}
|
||||
|
||||
newTags.push({
|
||||
id: this.createRandomTagId(),
|
||||
isNew: true,
|
||||
isNew: this.isNew(name),
|
||||
name,
|
||||
});
|
||||
this.setTags(newTags);
|
||||
|
@ -119,7 +119,7 @@ const ReportDialog = (props) => {
|
||||
onChange={onChangeTextareaValue}
|
||||
autoFocus
|
||||
areaSelect
|
||||
heightTextArea={72}
|
||||
heightTextArea="72px"
|
||||
fontSize={13}
|
||||
/>
|
||||
<div className="report-wrapper">
|
||||
|
@ -145,7 +145,7 @@ const EmbeddingBody = ({ t, link, requestToken, roomId }) => {
|
||||
iconName={CopyReactSvgUrl}
|
||||
onClick={onCopyLink}
|
||||
/>
|
||||
<Textarea isReadOnly value={codeBlock} heightTextArea={150} />
|
||||
<Textarea isReadOnly value={codeBlock} heightTextArea="150px" />
|
||||
</div>
|
||||
</div>
|
||||
</StyledBody>
|
||||
|
@ -97,7 +97,7 @@ const CommentEditor = ({
|
||||
onChange={onChangeInputValue}
|
||||
autoFocus
|
||||
areaSelect
|
||||
heightTextArea={54}
|
||||
heightTextArea="54px"
|
||||
fontSize={13}
|
||||
/>
|
||||
<div className="property-comment_editor-editor-buttons">
|
||||
|
@ -64,6 +64,7 @@ import {
|
||||
getCategoryUrl,
|
||||
} from "SRC_DIR/helpers/utils";
|
||||
import { getLogoFromPath } from "@docspace/shared/utils";
|
||||
import TariffBar from "SRC_DIR/components/TariffBar";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
@ -209,6 +210,7 @@ const SectionHeaderContent = (props) => {
|
||||
getAccountsCheckboxItemLabel,
|
||||
setAccountsSelected,
|
||||
isOwner,
|
||||
isCollaborator,
|
||||
setInvitePanelOptions,
|
||||
isEmptyPage,
|
||||
|
||||
@ -776,8 +778,11 @@ const SectionHeaderContent = (props) => {
|
||||
label: t("Files:CreateRoom"),
|
||||
key: "create-room",
|
||||
icon: CatalogRoomsReactSvgUrl,
|
||||
onClick: onClickCreateRoom,
|
||||
disabled: selectedFolder.rootFolderType !== FolderType.USER,
|
||||
onClick: () => {
|
||||
onClickCreateRoom({ title: selectedFolder.title, isFolder: true });
|
||||
},
|
||||
disabled:
|
||||
isCollaborator || selectedFolder.rootFolderType !== FolderType.USER,
|
||||
},
|
||||
{
|
||||
id: "option_leave-room",
|
||||
@ -1108,6 +1113,7 @@ const SectionHeaderContent = (props) => {
|
||||
showRootFolderTitle={insideTheRoom}
|
||||
currentDeviceType={currentDeviceType}
|
||||
isFrame={isFrame}
|
||||
tariffBar={<TariffBar />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -1135,6 +1141,7 @@ export default inject(
|
||||
}) => {
|
||||
const isOwner = auth.userStore.user?.isOwner;
|
||||
const isAdmin = auth.userStore.user?.isAdmin;
|
||||
const isCollaborator = auth?.userStore?.user?.isCollaborator;
|
||||
|
||||
const {
|
||||
setSelected,
|
||||
@ -1397,6 +1404,7 @@ export default inject(
|
||||
setAccountsSelected,
|
||||
isOwner,
|
||||
isAdmin,
|
||||
isCollaborator,
|
||||
setInvitePanelOptions,
|
||||
isEmptyPage,
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { TableGroupMenu } from "@docspace/shared/components/table";
|
||||
import { DropDownItem } from "@docspace/shared/components/drop-down-item";
|
||||
import LoaderSectionHeader from "../loaderSectionHeader";
|
||||
import { tablet, desktop } from "@docspace/shared/utils";
|
||||
import { mobile, tablet, desktop } from "@docspace/shared/utils";
|
||||
import withLoading from "SRC_DIR/HOCs/withLoading";
|
||||
import { Badge } from "@docspace/shared/components/badge";
|
||||
import {
|
||||
@ -21,6 +21,7 @@ import {
|
||||
checkPropertyByLink,
|
||||
} from "../../../utils";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import TariffBar from "SRC_DIR/components/TariffBar";
|
||||
|
||||
const HeaderContainer = styled.div`
|
||||
position: relative;
|
||||
@ -105,6 +106,24 @@ const HeaderContainer = styled.div`
|
||||
line-height: 59px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
h1 {
|
||||
line-height: 53px;
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize("18px")};
|
||||
}
|
||||
}
|
||||
|
||||
.tariff-bar {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -326,6 +345,10 @@ const SectionHeaderContent = (props) => {
|
||||
)}
|
||||
</div>
|
||||
</Headline>
|
||||
<div className="tariff-bar">
|
||||
<TariffBar />
|
||||
</div>
|
||||
|
||||
{props.addUsers && (
|
||||
<div className="action-wrapper">
|
||||
<IconButton
|
||||
|
@ -153,7 +153,7 @@ const Frame = styled(Box)`
|
||||
border: 1px solid #d0d5da;
|
||||
|
||||
width: ${(props) => (props.width ? props.width : "100%")};
|
||||
height: ${(props) => (props.height ? props.height : "400px")};
|
||||
height: calc(${(props) => (props.height ? props.height : "400px")} + 2px);
|
||||
|
||||
@media ${tablet} {
|
||||
margin-top: 4px;
|
||||
@ -508,7 +508,7 @@ const PortalIntegration = (props) => {
|
||||
<CategorySubHeader className="copy-window-code">
|
||||
{t("CopyWindowCode")}
|
||||
</CategorySubHeader>
|
||||
<Textarea value={codeBlock} heightTextArea={153} />
|
||||
<Textarea value={codeBlock} heightTextArea="153px" />
|
||||
</>
|
||||
);
|
||||
|
||||
|
@ -27,7 +27,7 @@ const GetCodeDialog = (props) => {
|
||||
<ModalDialog visible={visible} isLarge onClose={onClose}>
|
||||
<ModalDialog.Header>{t("CopyWindowCode")}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<StyledTextarea isReadOnly heightTextArea={180} value={codeBlock} />
|
||||
<StyledTextarea isReadOnly heightTextArea="180px" value={codeBlock} />
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
|
@ -4,17 +4,16 @@ import { tablet } from "@docspace/shared/utils";
|
||||
export const StyledHeader = styled.div`
|
||||
position: relative;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: ${(props) =>
|
||||
props.showContextButton ? "auto auto auto 1fr" : "auto 1fr"};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@media ${tablet} {
|
||||
grid-template-columns: ${(props) =>
|
||||
props.showContextButton ? "auto 1fr auto" : "auto 1fr"};
|
||||
}
|
||||
|
||||
.action-button {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
@ -24,6 +23,7 @@ export const StyledHeader = styled.div`
|
||||
margin-left: 16px;
|
||||
`}
|
||||
@media ${tablet} {
|
||||
flex-direction: row-reverse;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
@ -45,6 +45,17 @@ export const StyledHeader = styled.div`
|
||||
`}
|
||||
}
|
||||
}
|
||||
|
||||
.tariff-bar {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
}
|
||||
}
|
||||
.arrow-button {
|
||||
${(props) =>
|
||||
@ -60,6 +71,7 @@ export const StyledHeader = styled.div`
|
||||
}
|
||||
|
||||
.header-headline {
|
||||
white-space: nowrap;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
|
@ -19,6 +19,7 @@ import { DeleteOwnerProfileDialog } from "SRC_DIR/components/dialogs";
|
||||
import { StyledHeader } from "./StyledHeader";
|
||||
import RoomsFilter from "@docspace/shared/api/rooms/filter";
|
||||
import { RoomSearchArea } from "@docspace/shared/enums";
|
||||
import TariffBar from "SRC_DIR/components/TariffBar";
|
||||
|
||||
const Header = (props) => {
|
||||
const {
|
||||
@ -139,13 +140,13 @@ const Header = (props) => {
|
||||
className="arrow-button"
|
||||
/>
|
||||
|
||||
<Headline className="header-headline" type="content" truncate={true}>
|
||||
<Headline className="header-headline" type="content">
|
||||
{t("Profile:MyProfile")}
|
||||
{profile?.isLDAP && ` (${t("PeopleTranslations:LDAPLbl")})`}
|
||||
</Headline>
|
||||
<div className="action-button">
|
||||
{((isAdmin && !profile?.isOwner) || isMe) && (
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
title={t("Common:Actions")}
|
||||
iconName={VerticalDotsReactSvgUrl}
|
||||
@ -156,6 +157,11 @@ const Header = (props) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="tariff-bar">
|
||||
<TariffBar />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{deleteSelfProfileDialog && (
|
||||
<DeleteSelfProfileDialog
|
||||
visible={deleteSelfProfileDialog}
|
||||
|
@ -1,11 +1,16 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import ErrorContainer from "@docspace/common/components/ErrorContainer";
|
||||
|
||||
const RoomErrors = ({ t, tReady, isInvalid }) => {
|
||||
const headerText = isInvalid ? t("InvalidLink") : t("Common:ExpiredLink");
|
||||
const bodyText = isInvalid ? t("LinkDoesNotExist") : t("LinkHasExpired");
|
||||
|
||||
useEffect(() => {
|
||||
frameCallCommand("setIsLoaded");
|
||||
}, []);
|
||||
|
||||
return tReady ? (
|
||||
<ErrorContainer headerText={headerText} bodyText={bodyText} />
|
||||
) : (
|
||||
|
@ -7,6 +7,7 @@ import { FieldContainer } from "@docspace/shared/components/field-container";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { StyledPage, StyledBody, StyledContent } from "./RoomStyles";
|
||||
// import { createPasswordHash } from "@docspace/shared/utils/common";
|
||||
import { frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { FormWrapper } from "@docspace/shared/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
@ -27,6 +28,8 @@ const RoomPassword = (props) => {
|
||||
|
||||
const inputRef = useRef(null);
|
||||
|
||||
useEffect(() => frameCallCommand("setIsLoaded"), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
|
@ -274,7 +274,7 @@ const VersionRow = (props) => {
|
||||
className="version_edit-comment"
|
||||
onChange={onChange}
|
||||
fontSize={12}
|
||||
heightTextArea={54}
|
||||
heightTextArea="54px"
|
||||
value={commentValue}
|
||||
isDisabled={isSavingComment}
|
||||
autoFocus={true}
|
||||
|
@ -1529,10 +1529,14 @@ class ContextOptionsStore {
|
||||
});
|
||||
}
|
||||
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || { isCollaborator: false };
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || {
|
||||
isCollaborator: false,
|
||||
};
|
||||
|
||||
const newOptions = options.filter(
|
||||
(option, index) => !(index === 0 && option.key === "separator1") && !(isCollaborator && option.key === "create-room")
|
||||
(option, index) =>
|
||||
!(index === 0 && option.key === "separator1") &&
|
||||
!(isCollaborator && option.key === "create-room")
|
||||
);
|
||||
|
||||
return newOptions;
|
||||
@ -1785,10 +1789,14 @@ class ContextOptionsStore {
|
||||
},
|
||||
];
|
||||
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || { isCollaborator: false };
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || {
|
||||
isCollaborator: false,
|
||||
};
|
||||
|
||||
const newOptions = options.filter(
|
||||
(option, index) => !(index === 0 && option.key === "separator1") && !(isCollaborator && option.key === "create-room")
|
||||
(option, index) =>
|
||||
!(index === 0 && option.key === "separator1") &&
|
||||
!(isCollaborator && option.key === "create-room")
|
||||
);
|
||||
|
||||
return newOptions;
|
||||
|
@ -1606,9 +1606,12 @@ class FilesActionStore {
|
||||
|
||||
return !allFilesIsEditing && canDelete && hasSelection;
|
||||
case "create-room":
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || { isCollaborator: false };
|
||||
const { isCollaborator } = this.authStore?.userStore?.user || {
|
||||
isCollaborator: false,
|
||||
};
|
||||
|
||||
const canCreateRoom = !isCollaborator && rootFolderType === FolderType.USER;
|
||||
const canCreateRoom =
|
||||
!isCollaborator && rootFolderType === FolderType.USER;
|
||||
|
||||
return canCreateRoom;
|
||||
}
|
||||
@ -1746,9 +1749,12 @@ class FilesActionStore {
|
||||
this.processCreatingRoomFromData = processCreatingRoomFromData;
|
||||
};
|
||||
|
||||
onClickCreateRoom = () => {
|
||||
onClickCreateRoom = (item) => {
|
||||
this.setProcessCreatingRoomFromData(true);
|
||||
const event = new Event(Events.ROOM_CREATE);
|
||||
if (item && item.isFolder) {
|
||||
event.title = item.title;
|
||||
}
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@ import { ZendeskAPI } from "@docspace/shared/components/zendesk";
|
||||
import { LIVE_CHAT_LOCAL_STORAGE_KEY } from "@docspace/shared/constants";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { isDesktop, isTablet } from "@docspace/shared/utils";
|
||||
import TariffBar from "SRC_DIR/components/TariffBar";
|
||||
|
||||
const PROXY_HOMEPAGE_URL = combineUrl(window.DocSpaceConfig?.proxy?.url, "/");
|
||||
const PROFILE_SELF_URL = combineUrl(PROXY_HOMEPAGE_URL, "/profile");
|
||||
@ -332,6 +333,7 @@ class ProfileActionsStore {
|
||||
icon: PaymentsReactSvgUrl,
|
||||
label: t("Common:PaymentsTitle"),
|
||||
onClick: this.onPaymentsClick,
|
||||
additionalElement: <TariffBar />,
|
||||
},
|
||||
{
|
||||
isSeparator: true,
|
||||
|
@ -180,7 +180,7 @@ const RecoverAccessModalDialog: React.FC<IRecoverAccessModalDialogProps> = ({
|
||||
value={description}
|
||||
onChange={onChangeDescription}
|
||||
isDisabled={loading}
|
||||
heightTextArea={70}
|
||||
heightTextArea="70px"
|
||||
/>
|
||||
</FieldContainer>
|
||||
</ModalDialog.Body>
|
||||
|
@ -23,8 +23,8 @@ import {
|
||||
import { EditorWrapper } from "../components/StyledEditor";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import withDialogs from "../helpers/withDialogs";
|
||||
import { assign, frameCallEvent } from "@docspace/shared/utils/common";
|
||||
import { getEditorTheme, frameCallCommand } from "@docspace/shared/utils";
|
||||
import { assign, frameCallEvent, frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import { getEditorTheme } from "@docspace/shared/utils";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { DocumentEditor } from "@onlyoffice/document-editor-react";
|
||||
import ErrorContainer from "@docspace/common/components/ErrorContainer";
|
||||
|
@ -9,7 +9,7 @@ import { ReactSVG } from "react-svg";
|
||||
import { LoginFormWrapper } from "./StyledLogin";
|
||||
import BarLogo from "PUBLIC_DIR/images/danger.alert.react.svg";
|
||||
import { Dark, Base } from "@docspace/shared/themes";
|
||||
import { getBgPattern } from "@docspace/shared/utils/common";
|
||||
import { getBgPattern, frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import { getLogoFromPath } from "@docspace/shared/utils";
|
||||
import { useMounted } from "../helpers/useMounted";
|
||||
import useIsomorphicLayoutEffect from "../hooks/useIsomorphicLayoutEffect";
|
||||
@ -57,6 +57,7 @@ const Form: React.FC<ILoginProps> = ({ theme, setTheme, logoUrls }) => {
|
||||
? Dark
|
||||
: Base;
|
||||
setTheme(theme);
|
||||
frameCallCommand("setIsLoaded");
|
||||
}, []);
|
||||
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
|
@ -22,7 +22,7 @@ import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
|
||||
import SSOIcon from "PUBLIC_DIR/images/sso.react.svg";
|
||||
import { Dark, Base } from "@docspace/shared/themes";
|
||||
import { useMounted } from "../helpers/useMounted";
|
||||
import { getBgPattern } from "@docspace/shared/utils/common";
|
||||
import { getBgPattern, frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import useIsomorphicLayoutEffect from "../hooks/useIsomorphicLayoutEffect";
|
||||
import { getLogoFromPath, getSystemTheme } from "@docspace/shared/utils";
|
||||
import { TenantStatus } from "@docspace/shared/enums";
|
||||
@ -82,6 +82,7 @@ const Login: React.FC<ILoginProps> = ({
|
||||
const systemTheme = getSystemTheme();
|
||||
const theme = themes[systemTheme];
|
||||
setTheme(theme);
|
||||
frameCallCommand("setIsLoaded");
|
||||
}, []);
|
||||
|
||||
const ssoExists = () => {
|
||||
|
@ -74,24 +74,11 @@ export interface ArticleAlertsProps {
|
||||
articleAlertsData?: { current: string; available: string[] };
|
||||
incrementIndexOfArticleAlertsData?: () => void;
|
||||
showText?: boolean;
|
||||
isNonProfit?: boolean;
|
||||
isGracePeriod?: boolean;
|
||||
isFreeTariff?: boolean;
|
||||
isPaymentPageAvailable?: boolean;
|
||||
isTeamTrainingAlertAvailable?: boolean;
|
||||
isSubmitToGalleryAlertAvailable?: boolean;
|
||||
isLicenseExpiring?: boolean;
|
||||
isLicenseDateExpired?: boolean;
|
||||
isEnterprise?: boolean;
|
||||
isTrial?: boolean;
|
||||
standalone?: boolean;
|
||||
currentTariffPlanTitle?: string;
|
||||
toggleArticleOpen?: TToggleArticleOpen;
|
||||
bookTrainingEmail?: string;
|
||||
removeAlertFromArticleAlertsData?: TRemoveAlert;
|
||||
setSubmitToGalleryDialogVisible?: (value: boolean) => void;
|
||||
trialDaysLeft?: number;
|
||||
paymentDate?: Date;
|
||||
}
|
||||
|
||||
export interface ArticleAppsProps {
|
||||
|
@ -280,30 +280,17 @@ const Article = ({
|
||||
incrementIndexOfArticleAlertsData={
|
||||
incrementIndexOfArticleAlertsData
|
||||
}
|
||||
isNonProfit={isNonProfit}
|
||||
isEnterprise={isEnterprise}
|
||||
isFreeTariff={isFreeTariff}
|
||||
isGracePeriod={isGracePeriod}
|
||||
isLicenseDateExpired={isLicenseDateExpired}
|
||||
isLicenseExpiring={isLicenseExpiring}
|
||||
isPaymentPageAvailable={isPaymentPageAvailable}
|
||||
isSubmitToGalleryAlertAvailable={
|
||||
isSubmitToGalleryAlertAvailable
|
||||
}
|
||||
isTeamTrainingAlertAvailable={isTeamTrainingAlertAvailable}
|
||||
isTrial={isTrial}
|
||||
standalone={standalone}
|
||||
bookTrainingEmail={bookTrainingEmail}
|
||||
removeAlertFromArticleAlertsData={
|
||||
removeAlertFromArticleAlertsData
|
||||
}
|
||||
currentTariffPlanTitle={currentTariffPlanTitle}
|
||||
toggleArticleOpen={toggleArticleOpen}
|
||||
setSubmitToGalleryDialogVisible={
|
||||
setSubmitToGalleryDialogVisible
|
||||
}
|
||||
trialDaysLeft={trialDaysLeft}
|
||||
paymentDate={paymentDate}
|
||||
/>
|
||||
)}
|
||||
{withDevTools && (
|
||||
|
@ -4,8 +4,6 @@ import { ArticleAlerts } from "../../../enums";
|
||||
|
||||
import ArticleTeamTrainingAlert from "./TeamTrainingAlert";
|
||||
import ArticleSubmitToFormGalleryAlert from "./SubmitToFormGalleryAlert";
|
||||
import ArticlePaymentAlert from "./PaymentAlert";
|
||||
import ArticleEnterpriseAlert from "./EnterpriseAlert";
|
||||
|
||||
import { ArticleAlertsProps } from "../Article.types";
|
||||
import { StyledArticleAlertsComponent } from "../Article.styled";
|
||||
@ -14,24 +12,11 @@ const ArticleAlertsComponent = ({
|
||||
articleAlertsData,
|
||||
incrementIndexOfArticleAlertsData,
|
||||
showText,
|
||||
isNonProfit,
|
||||
isGracePeriod,
|
||||
isFreeTariff,
|
||||
isPaymentPageAvailable,
|
||||
isTeamTrainingAlertAvailable,
|
||||
isSubmitToGalleryAlertAvailable,
|
||||
isLicenseExpiring,
|
||||
isLicenseDateExpired,
|
||||
isEnterprise,
|
||||
isTrial,
|
||||
standalone,
|
||||
currentTariffPlanTitle,
|
||||
toggleArticleOpen,
|
||||
bookTrainingEmail,
|
||||
removeAlertFromArticleAlertsData,
|
||||
setSubmitToGalleryDialogVisible,
|
||||
paymentDate,
|
||||
trialDaysLeft,
|
||||
}: ArticleAlertsProps) => {
|
||||
const currentAlert = articleAlertsData?.current;
|
||||
const availableAlerts = articleAlertsData?.available;
|
||||
@ -40,46 +25,8 @@ const ArticleAlertsComponent = ({
|
||||
incrementIndexOfArticleAlertsData?.();
|
||||
}, [incrementIndexOfArticleAlertsData]);
|
||||
|
||||
const paymentsAlertsComponent = () => {
|
||||
if (!standalone) {
|
||||
return (
|
||||
isPaymentPageAvailable &&
|
||||
!isNonProfit &&
|
||||
(isFreeTariff || isGracePeriod) &&
|
||||
showText && (
|
||||
<ArticlePaymentAlert
|
||||
isFreeTariff={isFreeTariff}
|
||||
currentTariffPlanTitle={currentTariffPlanTitle}
|
||||
toggleArticleOpen={toggleArticleOpen}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const isVisibleStandaloneAlert =
|
||||
isTrial || isLicenseExpiring || isLicenseDateExpired;
|
||||
|
||||
return (
|
||||
isPaymentPageAvailable &&
|
||||
isEnterprise &&
|
||||
isVisibleStandaloneAlert &&
|
||||
showText && (
|
||||
<ArticleEnterpriseAlert
|
||||
toggleArticleOpen={toggleArticleOpen}
|
||||
isLicenseDateExpired={isLicenseDateExpired}
|
||||
trialDaysLeft={trialDaysLeft}
|
||||
isTrial={isTrial}
|
||||
paymentDate={paymentDate}
|
||||
isEnterprise={isEnterprise}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledArticleAlertsComponent>
|
||||
{paymentsAlertsComponent()}
|
||||
|
||||
{isTeamTrainingAlertAvailable &&
|
||||
showText &&
|
||||
availableAlerts?.includes(ArticleAlerts.TeamTraining) &&
|
||||
|
@ -1,102 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { useTheme } from "styled-components";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { combineUrl } from "../../../utils/combineUrl";
|
||||
import { RectangleSkeleton } from "../../../skeletons";
|
||||
|
||||
import AlertComponent from "../../alert";
|
||||
|
||||
import { ArticleEnterpriseAlertProps } from "../Article.types";
|
||||
|
||||
const PROXY_BASE_URL = combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
"/portal-settings",
|
||||
);
|
||||
|
||||
const ArticleEnterpriseAlert = ({
|
||||
toggleArticleOpen,
|
||||
isLicenseDateExpired,
|
||||
trialDaysLeft,
|
||||
isTrial,
|
||||
paymentDate,
|
||||
isEnterprise,
|
||||
}: ArticleEnterpriseAlertProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { t, ready } = useTranslation("Common");
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isClose, setIsClose] = useState<string | boolean | null>(
|
||||
localStorage.getItem("enterpriseAlertClose"),
|
||||
);
|
||||
|
||||
const onCloseClick = () => {
|
||||
localStorage.setItem("enterpriseAlertClose", "true");
|
||||
setIsClose(true);
|
||||
};
|
||||
|
||||
const onAlertClick = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
PROXY_BASE_URL,
|
||||
"/payments/portal-payments",
|
||||
);
|
||||
navigate(paymentPageUrl);
|
||||
toggleArticleOpen?.();
|
||||
};
|
||||
|
||||
const titleFunction = () => {
|
||||
if (isTrial) {
|
||||
if (isLicenseDateExpired) return t("Common:TrialExpired");
|
||||
return t("Common:TrialDaysLeft", { count: trialDaysLeft });
|
||||
}
|
||||
|
||||
return t("TariffEnterprise");
|
||||
};
|
||||
|
||||
const descriptionFunction = () => {
|
||||
if (isLicenseDateExpired) {
|
||||
if (isTrial) return;
|
||||
|
||||
return t("Common:SubscriptionExpired");
|
||||
}
|
||||
|
||||
return t("Common:SubscriptionIsExpiring", { date: paymentDate });
|
||||
};
|
||||
|
||||
const title = titleFunction();
|
||||
|
||||
const additionalDescription = t("Common:RenewSubscription");
|
||||
|
||||
const description = descriptionFunction();
|
||||
|
||||
const color = isLicenseDateExpired
|
||||
? theme.catalog.paymentAlert.warningColor
|
||||
: theme.catalog.paymentAlert.color;
|
||||
|
||||
const isShowLoader = !ready;
|
||||
|
||||
if (isEnterprise && isClose) return null;
|
||||
|
||||
return isShowLoader ? (
|
||||
<RectangleSkeleton width="210px" height="88px" />
|
||||
) : (
|
||||
<AlertComponent
|
||||
id="document_catalog-payment-alert"
|
||||
borderColor={color}
|
||||
titleColor={color}
|
||||
onAlertClick={onAlertClick}
|
||||
onCloseClick={onCloseClick}
|
||||
title={title}
|
||||
titleFontSize="11px"
|
||||
description={description}
|
||||
additionalDescription={additionalDescription}
|
||||
needArrowIcon={isTrial}
|
||||
needCloseIcon={!isTrial}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArticleEnterpriseAlert;
|
@ -1,75 +0,0 @@
|
||||
import React from "react";
|
||||
import { useTheme } from "styled-components";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation, Trans } from "react-i18next";
|
||||
|
||||
import { combineUrl } from "../../../utils/combineUrl";
|
||||
import { RectangleSkeleton } from "../../../skeletons";
|
||||
|
||||
import AlertComponent from "../../alert";
|
||||
import { ArticlePaymentAlertProps } from "../Article.types";
|
||||
|
||||
const PROXY_BASE_URL = combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
"/portal-settings",
|
||||
);
|
||||
|
||||
const ArticlePaymentAlert = ({
|
||||
isFreeTariff,
|
||||
currentTariffPlanTitle,
|
||||
toggleArticleOpen,
|
||||
}: ArticlePaymentAlertProps) => {
|
||||
const { t, ready } = useTranslation("Common");
|
||||
const theme = useTheme();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onClick = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
PROXY_BASE_URL,
|
||||
"/payments/portal-payments",
|
||||
);
|
||||
navigate(paymentPageUrl);
|
||||
toggleArticleOpen?.();
|
||||
};
|
||||
|
||||
const title = isFreeTariff ? (
|
||||
<Trans t={t} i18nKey="FreeStartupPlan" ns="Common">
|
||||
{{ planName: currentTariffPlanTitle }}
|
||||
</Trans>
|
||||
) : (
|
||||
t("Common:LatePayment")
|
||||
);
|
||||
|
||||
const description = isFreeTariff
|
||||
? t("Common:GetMoreOptions")
|
||||
: t("Common:PayBeforeTheEndGracePeriod");
|
||||
|
||||
const additionalDescription = isFreeTariff
|
||||
? t("Common:ActivatePremiumFeatures")
|
||||
: t("Common:GracePeriodActivated");
|
||||
|
||||
const color = isFreeTariff
|
||||
? theme.catalog.paymentAlert.color
|
||||
: theme.catalog.paymentAlert.warningColor;
|
||||
|
||||
const isShowLoader = !ready;
|
||||
|
||||
return isShowLoader ? (
|
||||
<RectangleSkeleton width="210px" height="88px" />
|
||||
) : (
|
||||
<AlertComponent
|
||||
id="document_catalog-payment-alert"
|
||||
borderColor={color}
|
||||
titleColor={color}
|
||||
onAlertClick={onClick}
|
||||
title={title}
|
||||
titleFontSize="11px"
|
||||
description={description}
|
||||
additionalDescription={additionalDescription}
|
||||
needArrowIcon
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArticlePaymentAlert;
|
@ -261,4 +261,11 @@ const IconWrapper = styled.div`
|
||||
`;
|
||||
IconWrapper.defaultProps = { theme: Base };
|
||||
|
||||
export { StyledDropdownItem, IconWrapper, WrapperToggle, WrapperBadge };
|
||||
const ElementWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl" ? css`margin-right: auto;` : css`margin-left: auto;`}
|
||||
`;
|
||||
|
||||
export { StyledDropdownItem, IconWrapper, WrapperToggle, WrapperBadge, ElementWrapper };
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
IconWrapper,
|
||||
WrapperToggle,
|
||||
WrapperBadge,
|
||||
ElementWrapper,
|
||||
} from "./DropDownItem.styled";
|
||||
import { DropDownItemProps } from "./DropDownItem.types";
|
||||
|
||||
@ -37,6 +38,7 @@ const DropDownItem = (props: DropDownItemProps) => {
|
||||
isSelected,
|
||||
isActiveDescendant,
|
||||
isBeta,
|
||||
additionalElement,
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslation(["Settings"]);
|
||||
@ -143,6 +145,10 @@ const DropDownItem = (props: DropDownItemProps) => {
|
||||
/>
|
||||
</WrapperBadge>
|
||||
)}
|
||||
|
||||
{additionalElement && (
|
||||
<ElementWrapper>{additionalElement}</ElementWrapper>
|
||||
)}
|
||||
</StyledDropdownItem>
|
||||
);
|
||||
};
|
||||
@ -164,3 +170,4 @@ DropDownItem.defaultProps = {
|
||||
};
|
||||
|
||||
export { DropDownItem };
|
||||
|
||||
|
@ -47,4 +47,6 @@ export interface DropDownItemProps {
|
||||
checked?: boolean;
|
||||
onClickSelectedItem?: () => void;
|
||||
isBeta?: boolean;
|
||||
additionalElement?: React.ReactNode;
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,8 @@ const StyledContainer = styled.div<{
|
||||
!props.isDropBoxComponent &&
|
||||
props.isDesktop &&
|
||||
css`
|
||||
width: fit-content;
|
||||
max-width: ${props.isInfoPanelVisible
|
||||
? `calc(100%)`
|
||||
: `calc(100% - 72px)`};
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
`}
|
||||
|
||||
display: grid;
|
||||
@ -210,7 +208,7 @@ const StyledContainer = styled.div<{
|
||||
}
|
||||
|
||||
grid-template-columns: ${(props) =>
|
||||
props.isRootFolder ? "1fr auto" : "29px 1fr auto"};
|
||||
props.isRootFolder ? "auto 1fr" : "29px auto 1fr"};
|
||||
}
|
||||
`;
|
||||
|
||||
@ -223,11 +221,11 @@ const StyledInfoPanelToggleColorThemeWrapper = styled(ColorTheme)<{
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
margin-right: 20px;
|
||||
transform: scaleX(-1);
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
margin-left: 20px;
|
||||
`}
|
||||
|
||||
margin-bottom: 1px;
|
||||
@ -278,18 +276,14 @@ const StyledControlButtonContainer = styled.div<{ isFrame?: boolean }>`
|
||||
`}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
gap: 16px;
|
||||
height: 32px;
|
||||
|
||||
@media ${tablet} {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 16px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 16px;
|
||||
`}
|
||||
min-width: 15px;
|
||||
|
||||
@media ${tablet} {
|
||||
@ -640,6 +634,26 @@ const StyledBox = styled.div<{
|
||||
|
||||
StyledBox.defaultProps = { theme: Base };
|
||||
|
||||
const StyledTariffWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
justify-content: left;
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
justify-content: right;
|
||||
margin-left: auto;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
`;
|
||||
|
||||
export {
|
||||
StyledContainer,
|
||||
StyledInfoPanelToggleColorThemeWrapper,
|
||||
@ -654,4 +668,5 @@ export {
|
||||
StyledText,
|
||||
StyledItem,
|
||||
StyledBox,
|
||||
StyledTariffWrapper,
|
||||
};
|
||||
|
@ -52,6 +52,7 @@ const Navigation = ({
|
||||
titleIcon,
|
||||
currentDeviceType,
|
||||
rootRoomTitle,
|
||||
tariffBar,
|
||||
|
||||
...rest
|
||||
}: INavigationProps) => {
|
||||
@ -253,6 +254,8 @@ const Navigation = ({
|
||||
isFrame={isFrame}
|
||||
isPublicRoom={isPublicRoom}
|
||||
isTrashFolder={isTrashFolder}
|
||||
tariffBar={tariffBar}
|
||||
title={title}
|
||||
/>
|
||||
</StyledContainer>
|
||||
{isDesktop && isTrashFolder && !isEmptyPage && (
|
||||
|
@ -60,6 +60,8 @@ export interface IControlButtonProps {
|
||||
isPublicRoom?: boolean;
|
||||
isTrashFolder?: boolean;
|
||||
isMobile?: boolean;
|
||||
tariffBar?: React.ReactNode;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface ITextProps {
|
||||
@ -160,4 +162,5 @@ export interface INavigationProps {
|
||||
titleIcon: string;
|
||||
currentDeviceType: DeviceType;
|
||||
rootRoomTitle: string;
|
||||
tariffBar: React.ReactNode;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import { StyledControlButtonContainer } from "../Navigation.styled";
|
||||
import {
|
||||
StyledControlButtonContainer,
|
||||
StyledTariffWrapper,
|
||||
} from "../Navigation.styled";
|
||||
import { IControlButtonProps } from "../Navigation.types";
|
||||
|
||||
import ToggleInfoPanelButton from "./ToggleInfoPanelBtn";
|
||||
@ -24,11 +27,14 @@ const ControlButtons = ({
|
||||
isPublicRoom,
|
||||
isTrashFolder,
|
||||
isMobile,
|
||||
tariffBar,
|
||||
title,
|
||||
}: IControlButtonProps) => {
|
||||
const toggleInfoPanelAction = () => {
|
||||
toggleInfoPanel?.();
|
||||
toggleDropBox?.();
|
||||
};
|
||||
const children = tariffBar ? React.cloneElement(tariffBar, { title }) : null;
|
||||
|
||||
return (
|
||||
<StyledControlButtonContainer isFrame={isFrame}>
|
||||
@ -124,8 +130,9 @@ const ControlButtons = ({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<StyledTariffWrapper>{children && children}</StyledTariffWrapper>
|
||||
</StyledControlButtonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ControlButtons);
|
||||
export default ControlButtons;
|
||||
|
@ -17,6 +17,10 @@ export interface ScrollbarProps {
|
||||
noScrollY?: boolean;
|
||||
/** Disable horizontal scrolling. */
|
||||
noScrollX?: boolean;
|
||||
/** Calculating height of content depending on number of lines */
|
||||
isFullHeight?: boolean;
|
||||
/** Calculated height of content depending on number of lines in pixels */
|
||||
fullHeight?: number;
|
||||
|
||||
onScroll?: React.UIEventHandler<HTMLDivElement>;
|
||||
scrollclass?: string;
|
||||
|
@ -20,7 +20,7 @@ import { Textarea } from "@docspace/shared/components/textarea";
|
||||
### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ---------------- | :------------: | :------: | :----: | :--------------------------------: | -------------------------------------------------------- |
|
||||
| ---------------- | :----------------: | :------: | :----: | :--------------------------------: | -------------------------------------------------------- |
|
||||
| `className` | `string` | - | - | - | Class name |
|
||||
| `id` | `string` | - | - | - | Used as HTML `id` property |
|
||||
| `isDisabled` | `bool` | - | - | `false` | Indicates that the field cannot be used |
|
||||
@ -32,6 +32,6 @@ import { Textarea } from "@docspace/shared/components/textarea";
|
||||
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
||||
| `value` | `string` | - | - | - | Value for Textarea |
|
||||
| `fontSize` | `number` | - | - | 13 | Value for font-size |
|
||||
| `heightTextArea` | `number` | - | - | - | Value for height text-area |
|
||||
| `heightTextArea` | `string`, `number` | - | - | - | Value for height text-area |
|
||||
| `isJSONField` | `bool` | - | - | `false` | Indicates that the field is displaying JSON object |
|
||||
| `copyInfoText` | `string` | - | - | `Content was copied successfully!` | Indicates the text of toast/informational alarm |
|
||||
|
@ -51,7 +51,7 @@ export const Default: Story = {
|
||||
name: "",
|
||||
tabIndex: 1,
|
||||
fontSize: 13,
|
||||
heightTextArea: 89,
|
||||
heightTextArea: "89px",
|
||||
value:
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae",
|
||||
isJSONField: false,
|
||||
@ -80,7 +80,7 @@ export const JsonViewer: Story = {
|
||||
name: "",
|
||||
tabIndex: 1,
|
||||
fontSize: 13,
|
||||
heightTextArea: 89,
|
||||
heightTextArea: "89px",
|
||||
value:
|
||||
'{"menu": {"id": "file","value": "File","popup": {"menuitem": [{"value": "New", "onclick": "CreateNewDoc()"},{"value": "Open", "onclick": "OpenDoc()"},{"value": "Close", "onclick": "CloseDoc()"}]}}}',
|
||||
isJSONField: true,
|
||||
|
@ -15,12 +15,14 @@ const ClearScrollbar = ({
|
||||
heightScale,
|
||||
hasError,
|
||||
heightTextAreaProp,
|
||||
isFullHeight,
|
||||
fullHeight,
|
||||
...props
|
||||
}: {
|
||||
isDisabled?: boolean;
|
||||
heightScale?: boolean;
|
||||
hasError?: boolean;
|
||||
heightTextAreaProp?: number;
|
||||
heightTextAreaProp?: string;
|
||||
ref?: React.Ref<HTMLDivElement>;
|
||||
} & ScrollbarProps) => <Scrollbar {...props} />;
|
||||
|
||||
@ -37,20 +39,26 @@ const StyledScrollbar = styled(ClearScrollbar)`
|
||||
}
|
||||
|
||||
width: ${(props) => props.theme.textArea.scrollWidth} !important;
|
||||
height: ${(props) => {
|
||||
height: calc(
|
||||
${(props) => {
|
||||
return props.heightScale
|
||||
? "67vh"
|
||||
: props.isFullHeight
|
||||
? `${props.fullHeight}px`
|
||||
: props.heightTextAreaProp
|
||||
? `${props.heightTextAreaProp + 2}px`
|
||||
? props.heightTextAreaProp
|
||||
: "91px";
|
||||
}} !important;
|
||||
}} + 2px
|
||||
) !important;
|
||||
|
||||
textarea {
|
||||
height: ${(props) => {
|
||||
return props.heightScale
|
||||
? "65vh"
|
||||
: props.isFullHeight
|
||||
? `${props.fullHeight}px`
|
||||
: props.heightTextAreaProp
|
||||
? `${props.heightTextAreaProp}px`
|
||||
? props.heightTextAreaProp
|
||||
: "89px";
|
||||
}};
|
||||
}
|
||||
@ -72,13 +80,11 @@ const ClearTextareaAutosize = React.forwardRef(
|
||||
paddingLeftProp,
|
||||
isJSONField,
|
||||
enableCopy,
|
||||
heightTextAreaProp,
|
||||
heightTextArea,
|
||||
...props
|
||||
}: TextareaProps & {
|
||||
disabled?: boolean;
|
||||
readOnly?: boolean;
|
||||
heightTextAreaProp?: number;
|
||||
},
|
||||
ref: React.Ref<HTMLTextAreaElement>,
|
||||
) => <TextareaAutosize {...props} ref={ref} />,
|
||||
@ -202,10 +208,26 @@ const CopyIconWrapper = styled.div<{
|
||||
|
||||
CopyIconWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const Wrapper = styled.div<{ enableCopy?: boolean; isJSONField?: boolean }>`
|
||||
const Wrapper = styled.div<{
|
||||
heightScale?: boolean;
|
||||
isFullHeight?: boolean;
|
||||
fullHeight?: number;
|
||||
heightTextArea?: string;
|
||||
enableCopy?: boolean;
|
||||
isJSONField?: boolean;
|
||||
}>`
|
||||
position: relative;
|
||||
|
||||
max-width: 1200px;
|
||||
height: ${(props) => {
|
||||
return props.heightScale
|
||||
? "65vh"
|
||||
: props.isFullHeight
|
||||
? `${props.fullHeight}px`
|
||||
: props.heightTextArea
|
||||
? props.heightTextArea
|
||||
: "89px";
|
||||
}};
|
||||
|
||||
.scroll-wrapper {
|
||||
margin-right: ${(props) =>
|
||||
@ -216,8 +238,7 @@ const Wrapper = styled.div<{ enableCopy?: boolean; isJSONField?: boolean }>`
|
||||
const Numeration = styled.pre<{ fontSize: string }>`
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize(props.fontSize)};
|
||||
font-size: ${(props) => props.theme.getCorrectFontSize(props.fontSize)}px;
|
||||
font-family: ${(props) => props.theme.fontFamily};
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
|
@ -71,12 +71,12 @@ describe("<Textarea />", () => {
|
||||
// onChange={jest.fn()}
|
||||
// value="value"
|
||||
// className="test"
|
||||
// heightTextArea={54}
|
||||
// heightTextArea="54px"
|
||||
// />
|
||||
// );
|
||||
|
||||
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
|
||||
// expect(wrapper.prop("heightTextArea")).toEqual(54);
|
||||
// expect(wrapper.prop("heightTextArea")).toEqual("54px");
|
||||
// });
|
||||
|
||||
// // @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
|
||||
|
@ -53,9 +53,9 @@ const Textarea = ({
|
||||
const lineHeight = 1.5;
|
||||
const padding = 7;
|
||||
const numberOfLines = modifiedValue.split("\n").length;
|
||||
const textareaHeight = isFullHeight
|
||||
? numberOfLines * fontSize * lineHeight + padding + 4
|
||||
: heightTextArea;
|
||||
const fullHeight = numberOfLines * fontSize * lineHeight + padding + 4;
|
||||
const stringifiedHeight =
|
||||
typeof heightTextArea === "number" ? `${heightTextArea}px` : heightTextArea;
|
||||
|
||||
const defaultPaddingLeft = 42;
|
||||
const numberOfDigits =
|
||||
@ -77,8 +77,8 @@ const Textarea = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (hasError !== isError) setIsError(hasError);
|
||||
}, [hasError, isError]);
|
||||
setIsError(hasError);
|
||||
}, [hasError]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsError(isJSONField && (!value || !isJSON(value)));
|
||||
@ -97,6 +97,10 @@ const Textarea = ({
|
||||
enableCopy={enableCopy}
|
||||
onClick={onTextareaClick}
|
||||
data-testid="textarea"
|
||||
heightScale={heightScale}
|
||||
heightTextArea={stringifiedHeight}
|
||||
isFullHeight={isFullHeight}
|
||||
fullHeight={fullHeight}
|
||||
>
|
||||
{enableCopy && (
|
||||
<CopyIconWrapper
|
||||
@ -118,7 +122,9 @@ const Textarea = ({
|
||||
isDisabled={isDisabled}
|
||||
hasError={isError}
|
||||
heightScale={heightScale}
|
||||
heightTextAreaProp={textareaHeight}
|
||||
heightTextAreaProp={stringifiedHeight}
|
||||
isFullHeight={isFullHeight}
|
||||
fullHeight={fullHeight}
|
||||
>
|
||||
<Toast />
|
||||
|
||||
@ -128,7 +134,6 @@ const Textarea = ({
|
||||
</Numeration>
|
||||
)}
|
||||
<StyledTextarea
|
||||
heightTextAreaProp={textareaHeight}
|
||||
id={id}
|
||||
paddingLeftProp={paddingLeftProp}
|
||||
isJSONField={isJSONField}
|
||||
|
@ -31,7 +31,7 @@ export interface TextareaProps {
|
||||
/** Font-size value */
|
||||
fontSize?: number;
|
||||
/** Text-area height value */
|
||||
heightTextArea?: number;
|
||||
heightTextArea?: string | number;
|
||||
/** Specifies the text color */
|
||||
color?: string;
|
||||
/** Default input property */
|
||||
@ -48,13 +48,16 @@ export interface TextareaProps {
|
||||
hasNumeration?: boolean;
|
||||
/** Calculating height of content depending on number of lines */
|
||||
isFullHeight?: boolean;
|
||||
/** Calculated height of content depending on number of lines in pixels */
|
||||
fullHeight?: number;
|
||||
|
||||
classNameCopyIcon?: string;
|
||||
paddingLeftProp?: string;
|
||||
}
|
||||
|
||||
export interface TextareaThemeProps extends TextareaProps {
|
||||
ref: React.LegacyRef<HTMLTextAreaElement>;
|
||||
heightTextAreaProp?: number;
|
||||
heightTextAreaProp?: string;
|
||||
$currentColorScheme?: TColorScheme;
|
||||
interfaceDirection?: string;
|
||||
}
|
||||
|
@ -300,6 +300,7 @@
|
||||
"Standard": "Standard",
|
||||
"SubmitToFormGallery": "Submit to Form Gallery",
|
||||
"SubmitToGallery": "Submit to Gallery",
|
||||
"SubscriptionExpiredTitle": "Subscription expired",
|
||||
"SubscriptionExpired": "Your subscription to support and updates has expired",
|
||||
"SubscriptionIsExpiring": "Your subscription is expiring on {{date}}",
|
||||
"Support": "Support",
|
||||
@ -314,6 +315,7 @@
|
||||
"Today": "Today",
|
||||
"TrialDaysLeft": "Trial {{count}} days",
|
||||
"TrialExpired": "Trial expired",
|
||||
"TryBusiness": "Try Business",
|
||||
"Type": "Type",
|
||||
"UTC": "UTC",
|
||||
"UnexpectedError": "An unexpected error occurred. Try again later or contact support.",
|
||||
|
@ -474,7 +474,9 @@
|
||||
target.innerHTML = this.config.destroyText;
|
||||
target.className = this.#classNames;
|
||||
|
||||
const targetFrame = document.getElementById(this.config.frameId);
|
||||
const targetFrame = document.getElementById(
|
||||
this.config.frameId + "-container"
|
||||
);
|
||||
|
||||
if (targetFrame) {
|
||||
window.removeEventListener("message", this.#onMessage, false);
|
||||
|
Loading…
Reference in New Issue
Block a user