Address code review comments (styling, clean-up css, re-org imports, math errors, etc).
Этот коммит содержится в:
26
webapp/channels/src/components/outlined_input/index.tsx
Обычный файл
26
webapp/channels/src/components/outlined_input/index.tsx
Обычный файл
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {OutlinedInput as MUIOutlineInput, OutlinedInputProps} from '@mui/material';
|
||||
|
||||
/**
|
||||
* A horizontal separator for use in menus.
|
||||
* @example
|
||||
* <OutlineInput
|
||||
* data-testid='my-input'
|
||||
* size='small|medium
|
||||
* value=10
|
||||
* onChange={myChangeHandler}
|
||||
* error=true
|
||||
* disabled=false
|
||||
* />
|
||||
*/
|
||||
|
||||
export function OutlinedInput(props: OutlinedInputProps) {
|
||||
return (
|
||||
<MUIOutlineInput
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {useOpenSelfHostedZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm';
|
||||
|
||||
import {useOpenSelfHostedZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm';
|
||||
import PaymentFailedSvg from 'components/common/svg_images_components/payment_failed_svg';
|
||||
import IconMessage from 'components/purchase_modal/icon_message';
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.72);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
@@ -24,7 +23,6 @@
|
||||
.seatsInput {
|
||||
width: 73px;
|
||||
margin-left: auto;
|
||||
font-family: 'Open Sans';
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
|
||||
@@ -46,7 +44,6 @@
|
||||
|
||||
.planName {
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.72);
|
||||
font-family: 'Metropolis';
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
text-transform: capitalize;
|
||||
@@ -54,7 +51,6 @@
|
||||
|
||||
.usage {
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.56);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -78,13 +74,11 @@
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
.costPerUser > span:first-child {
|
||||
font-family: 'Open Sans';
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.costPerUser > span:last-child {
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.72);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -94,14 +88,12 @@
|
||||
|
||||
.totalCostWarning > span:first-child {
|
||||
color: var(--sys-denim-center-channel-text);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.totalCostWarning > span:last-child {
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.72);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -119,7 +111,6 @@
|
||||
height: 35px;
|
||||
margin-bottom: 15px;
|
||||
color: var(--dnd-indicator);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-align: right;
|
||||
@@ -134,7 +125,6 @@
|
||||
|
||||
&__ChargedTodayDisclaimer {
|
||||
color: rgba(var(--sys-denim-center-channel-text-rgb), 0.72);
|
||||
font-family: 'Open Sans';
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {OutlinedInput} from '@mui/material';
|
||||
|
||||
import moment from 'moment-timezone';
|
||||
import React, {Fragment, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import React, {useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {useSelector} from 'react-redux';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {DocLinks} from 'utils/constants';
|
||||
|
||||
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
|
||||
import useGetSelfHostedProducts from 'components/common/hooks/useGetSelfHostedProducts';
|
||||
import ExternalLink from 'components/external_link';
|
||||
import {OutlinedInput} from 'components/outlined_input';
|
||||
|
||||
import {DocLinks} from 'utils/constants';
|
||||
import {findSelfHostedProductBySku} from 'utils/hosted_customer';
|
||||
|
||||
import './expansion_card.scss';
|
||||
import useGetSelfHostedProducts from 'components/common/hooks/useGetSelfHostedProducts';
|
||||
import {findSelfHostedProductBySku} from 'utils/hosted_customer';
|
||||
import ExternalLink from 'components/external_link';
|
||||
|
||||
const MONTHS_IN_YEAR = 12;
|
||||
const MAX_TRANSACTION_VALUE = 1_000_000 - 1;
|
||||
@@ -29,6 +30,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function SelfHostedExpansionCard(props: Props) {
|
||||
const intl = useIntl();
|
||||
const license = useSelector(getLicense);
|
||||
const startsAt = moment(parseInt(license.StartsAt, 10)).format('MMM. D, YYYY');
|
||||
const endsAt = moment(parseInt(license.ExpiresAt, 10)).format('MMM. D, YYYY');
|
||||
@@ -46,14 +48,11 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
};
|
||||
|
||||
const getCostPerUser = () => {
|
||||
if (isNaN(additionalSeats)) {
|
||||
return 0;
|
||||
}
|
||||
const monthsUntilExpiry = getMonthsUntilExpiry();
|
||||
return costPerMonth * monthsUntilExpiry;
|
||||
};
|
||||
|
||||
const getTotal = () => {
|
||||
const getPaymentTotal = () => {
|
||||
if (isNaN(additionalSeats)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -63,25 +62,29 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
|
||||
// Finds the maximum number of additional seats that is possible, taking into account
|
||||
// the stripe transaction limit. The maximum number of seats will follow the formula:
|
||||
// (StripeTransaction Limit - (Current_Seats * Price Per Seat)) / price_per_seat
|
||||
// (StripeTransaction Limit - (current_seats * yearly_price_per_seat)) / yearly_price_per_seat
|
||||
const getMaximumAdditionalSeats = () => {
|
||||
if (currentProduct === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const currentPaymentPrice = costPerMonth * props.licensedSeats;
|
||||
const currentPaymentPrice = costPerMonth * props.licensedSeats * 12;
|
||||
const remainingTransactionLimit = MAX_TRANSACTION_VALUE - currentPaymentPrice;
|
||||
const remainingSeats = Math.floor(remainingTransactionLimit / costPerMonth);
|
||||
const remainingSeats = Math.floor(remainingTransactionLimit / (costPerMonth * 12));
|
||||
return Math.max(0, remainingSeats);
|
||||
};
|
||||
|
||||
const maxAdditionalSeats = getMaximumAdditionalSeats();
|
||||
|
||||
const handleNewSeatsInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setOverMaxSeats(false);
|
||||
|
||||
const requestedSeats = parseInt(e.target.value, 10);
|
||||
|
||||
if (requestedSeats <= 0) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
setOverMaxSeats(false);
|
||||
|
||||
const overMaxAdditionalSeats = requestedSeats > maxAdditionalSeats;
|
||||
setOverMaxSeats(overMaxAdditionalSeats);
|
||||
|
||||
@@ -91,6 +94,10 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
props.updateSeats(finalSeatCount);
|
||||
};
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return intl.formatNumber(value, {style: 'currency', currency: 'USD'});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='SelfHostedExpansionRHSCard'>
|
||||
<div className='SelfHostedExpansionRHSCard__RHSCardTitle'>
|
||||
@@ -158,16 +165,6 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
}}
|
||||
/>
|
||||
}
|
||||
{maxAdditionalSeats === 0 &&
|
||||
<FormattedMessage
|
||||
id='self_hosted_expansion_rhs_card_additional_seats_limit_warning'
|
||||
defaultMessage='{warningIcon} Transaction amount limit reached.{break}Please contact sales'
|
||||
values={{
|
||||
break: <br/>,
|
||||
warningIcon: <WarningIcon additionalClassName={'SelfHostedExpansionRHSCard__warning'}/>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className='SelfHostedExpansionRHSCard__cost_breakdown'>
|
||||
<div className='costPerUser'>
|
||||
@@ -179,15 +176,15 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
<FormattedMessage
|
||||
id='self_hosted_expansion_rhs_card_cost_per_user_breakdown'
|
||||
/* eslint-disable no-template-curly-in-string*/
|
||||
defaultMessage='${costPerUser} x {monthsUntilExpiry} months'
|
||||
defaultMessage='{costPerUser} x {monthsUntilExpiry} months'
|
||||
values={{
|
||||
costPerUser: costPerMonth.toFixed(2),
|
||||
costPerUser: formatCurrency(costPerMonth),
|
||||
monthsUntilExpiry: getMonthsUntilExpiry(),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='costAmount'>
|
||||
<span>{'$' + getCostPerUser().toFixed(2)}</span>
|
||||
<span>{formatCurrency(getCostPerUser())}</span>
|
||||
</div>
|
||||
<div className='totalCostWarning'>
|
||||
<FormattedMessage
|
||||
@@ -201,7 +198,7 @@ export default function SelfHostedExpansionCard(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
<span className='totalCostAmount'>
|
||||
<span>{'$' + getTotal().toFixed(2)}</span>
|
||||
<span>{formatCurrency(getPaymentTotal()) }</span>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -2,55 +2,51 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {StripeCardElementChangeEvent} from '@stripe/stripe-js';
|
||||
|
||||
import {getLicenseConfig} from 'mattermost-redux/actions/general';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getCurrentUser, getFilteredUsersStats} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getSelfHostedSignupProgress} from 'mattermost-redux/selectors/entities/hosted_customer';
|
||||
import {DispatchFunc} from 'mattermost-redux/types/actions';
|
||||
import {HostedCustomerTypes} from 'mattermost-redux/action_types';
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
import {isDevModeEnabled} from 'selectors/general';
|
||||
|
||||
import {closeModal} from 'actions/views/modals';
|
||||
import {pageVisited} from 'actions/telemetry_actions';
|
||||
import {confirmSelfHostedExpansion} from 'actions/hosted_customer';
|
||||
|
||||
import {ValueOf} from '@mattermost/types/utilities';
|
||||
import {SelfHostedSignupCustomerResponse, SelfHostedSignupProgress} from '@mattermost/types/hosted_customer';
|
||||
|
||||
import UpgradeSvg from 'components/common/svg_images_components/upgrade_svg';
|
||||
import RootPortal from 'components/root_portal';
|
||||
import ContactSalesLink from 'components/self_hosted_purchases/contact_sales_link';
|
||||
import ErrorPage from 'components/self_hosted_purchases/self_hosted_expansion_modal/error_page';
|
||||
import SuccessPage from 'components/self_hosted_purchases/self_hosted_expansion_modal/success_page';
|
||||
import Submitting from './submitting';
|
||||
|
||||
import useLoadStripe from 'components/common/hooks/useLoadStripe';
|
||||
import CardInput, {CardInputType} from 'components/payment_form/card_input';
|
||||
import FullScreenModal from 'components/widgets/modals/full_screen_modal';
|
||||
import Input from 'components/widgets/inputs/input/input';
|
||||
|
||||
import BackgroundSvg from 'components/common/svg_images_components/background_svg';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import StripeProvider from '../stripe_provider';
|
||||
|
||||
import {closeModal} from 'actions/views/modals';
|
||||
import {ModalIdentifiers, TELEMETRY_CATEGORIES} from 'utils/constants';
|
||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getCurrentUser, getFilteredUsersStats} from 'mattermost-redux/selectors/entities/users';
|
||||
import {pageVisited} from 'actions/telemetry_actions';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
import {HostedCustomerTypes} from 'mattermost-redux/action_types';
|
||||
import {getSelfHostedSignupProgress} from 'mattermost-redux/selectors/entities/hosted_customer';
|
||||
import {inferNames} from 'utils/hosted_customer';
|
||||
import {SelfHostedSignupCustomerResponse, SelfHostedSignupProgress} from '@mattermost/types/hosted_customer';
|
||||
import {isDevModeEnabled} from 'selectors/general';
|
||||
import {getLicenseConfig} from 'mattermost-redux/actions/general';
|
||||
import {confirmSelfHostedExpansion} from 'actions/hosted_customer';
|
||||
import {DispatchFunc} from 'mattermost-redux/types/actions';
|
||||
import {ValueOf} from '@mattermost/types/utilities';
|
||||
|
||||
import SelfHostedExpansionCard from './expansion_card';
|
||||
|
||||
import './self_hosted_expansion_modal.scss';
|
||||
|
||||
import {STORAGE_KEY_EXPANSION_IN_PROGRESS} from '../constants';
|
||||
import Terms from 'components/self_hosted_purchases/self_hosted_purchase_modal/terms';
|
||||
import Address from 'components/self_hosted_purchases/address';
|
||||
import ChooseDifferentShipping from 'components/choose_different_shipping';
|
||||
import Terms from 'components/self_hosted_purchases/self_hosted_purchase_modal/terms';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {ModalIdentifiers, TELEMETRY_CATEGORIES} from 'utils/constants';
|
||||
import {inferNames} from 'utils/hosted_customer';
|
||||
|
||||
import Submitting from './submitting';
|
||||
import StripeProvider from '../stripe_provider';
|
||||
import {STORAGE_KEY_EXPANSION_IN_PROGRESS} from '../constants';
|
||||
import SelfHostedExpansionCard from './expansion_card';
|
||||
import './self_hosted_expansion_modal.scss';
|
||||
|
||||
export interface FormState {
|
||||
cardName: string;
|
||||
@@ -358,7 +354,7 @@ export default function SelfHostedExpansionModal() {
|
||||
<div className='center'>
|
||||
<div
|
||||
className='form'
|
||||
data-testid='shpm-form'
|
||||
data-testid='expansion-modal'
|
||||
>
|
||||
<span className='section-title'>
|
||||
{intl.formatMessage({
|
||||
|
||||
@@ -38,14 +38,12 @@
|
||||
margin-right: 16px;
|
||||
|
||||
.DropdownInput {
|
||||
z-index: 99999;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.DropdownInput {
|
||||
position: relative;
|
||||
z-index: 999999;
|
||||
height: 36px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
@@ -73,7 +71,6 @@
|
||||
background: var(--center-channel-bg);
|
||||
|
||||
.Input {
|
||||
height: 32px;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
import {getSelfHostedSignupProgress} from 'mattermost-redux/selectors/entities/hosted_customer';
|
||||
|
||||
import {SelfHostedSignupProgress} from '@mattermost/types/hosted_customer';
|
||||
import {ValueOf} from '@mattermost/types/utilities';
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
justify-content: center;
|
||||
padding: 77px 107px;
|
||||
color: var(--center-channel-color);
|
||||
font-family: "Open Sans";
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import {useHistory} from 'react-router-dom';
|
||||
|
||||
import IconMessage from 'components/purchase_modal/icon_message';
|
||||
import PaymentSuccessStandardSvg from 'components/common/svg_images_components/payment_success_standard_svg';
|
||||
import {ConsolePages} from 'utils/constants';
|
||||
import BackgroundSvg from 'components/common/svg_images_components/background_svg';
|
||||
|
||||
import {ConsolePages} from 'utils/constants';
|
||||
|
||||
import './success_page.scss';
|
||||
|
||||
interface Props {
|
||||
@@ -69,9 +69,7 @@ export default function SelfHostedExpansionSuccessPage(props: Props) {
|
||||
testId='selfHostedExpansionSuccess'
|
||||
icon={icon}
|
||||
formattedButtonText={formattedButtonText}
|
||||
buttonHandler={() => {
|
||||
props.onClose();
|
||||
}}
|
||||
buttonHandler={props.onClose}
|
||||
/>
|
||||
<div className='background-svg'>
|
||||
<BackgroundSvg/>
|
||||
|
||||
@@ -4712,7 +4712,6 @@
|
||||
"select_team.join.icon": "Join Team Icon",
|
||||
"select_team.private.icon": "Private Team",
|
||||
"self_hosted_expansion_rhs_card_add_new_seats": "Add new seats",
|
||||
"self_hosted_expansion_rhs_card_additional_seats_limit_warning": "{warningIcon} Transaction amount limit reached.{break}Please contact sales",
|
||||
"self_hosted_expansion_rhs_card_cost_per_user_breakdown": "{costPerUser} x {monthsUntilExpiry} months",
|
||||
"self_hosted_expansion_rhs_card_cost_per_user_title": "Cost per user",
|
||||
"self_hosted_expansion_rhs_card_license_date": "{startsAt} - {endsAt}",
|
||||
|
||||
Ссылка в новой задаче
Block a user