require a minimum number of seats to be purchased to continue.
Этот коммит содержится в:
@@ -24,7 +24,7 @@ const MAX_TRANSACTION_VALUE = 1_000_000 - 1;
|
|||||||
interface Props {
|
interface Props {
|
||||||
canSubmit: boolean;
|
canSubmit: boolean;
|
||||||
licensedSeats: number;
|
licensedSeats: number;
|
||||||
initialSeats: number;
|
minimumSeats: number;
|
||||||
submit: () => void;
|
submit: () => void;
|
||||||
updateSeats: (seats: number) => void;
|
updateSeats: (seats: number) => void;
|
||||||
}
|
}
|
||||||
@@ -34,10 +34,10 @@ export default function SelfHostedExpansionCard(props: Props) {
|
|||||||
const license = useSelector(getLicense);
|
const license = useSelector(getLicense);
|
||||||
const startsAt = moment(parseInt(license.StartsAt, 10)).format('MMM. D, YYYY');
|
const startsAt = moment(parseInt(license.StartsAt, 10)).format('MMM. D, YYYY');
|
||||||
const endsAt = moment(parseInt(license.ExpiresAt, 10)).format('MMM. D, YYYY');
|
const endsAt = moment(parseInt(license.ExpiresAt, 10)).format('MMM. D, YYYY');
|
||||||
const [additionalSeats, setAdditionalSeats] = useState(props.initialSeats);
|
const [additionalSeats, setAdditionalSeats] = useState(props.minimumSeats);
|
||||||
const [overMaxSeats, setOverMaxSeats] = useState(false);
|
const [overMaxSeats, setOverMaxSeats] = useState(false);
|
||||||
const licenseExpiry = new Date(parseInt(license.ExpiresAt, 10));
|
const licenseExpiry = new Date(parseInt(license.ExpiresAt, 10));
|
||||||
const invalidAdditionalSeats = additionalSeats === 0 || isNaN(additionalSeats);
|
const invalidAdditionalSeats = additionalSeats === 0 || isNaN(additionalSeats) || additionalSeats < props.minimumSeats;
|
||||||
const [products] = useGetSelfHostedProducts();
|
const [products] = useGetSelfHostedProducts();
|
||||||
const currentProduct = findSelfHostedProductBySku(products, license.SkuShortName);
|
const currentProduct = findSelfHostedProductBySku(products, license.SkuShortName);
|
||||||
const costPerMonth = currentProduct?.price_per_seat || 0;
|
const costPerMonth = currentProduct?.price_per_seat || 0;
|
||||||
@@ -76,9 +76,9 @@ export default function SelfHostedExpansionCard(props: Props) {
|
|||||||
const maxAdditionalSeats = getMaximumAdditionalSeats();
|
const maxAdditionalSeats = getMaximumAdditionalSeats();
|
||||||
|
|
||||||
const handleNewSeatsInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleNewSeatsInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const requestedSeats = parseInt(e.target.value, 10);
|
let requestedSeats = parseInt(e.target.value, 10);
|
||||||
|
|
||||||
if (requestedSeats <= 0) {
|
if (!isNaN(requestedSeats) && requestedSeats <= 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -141,12 +141,11 @@ export default function SelfHostedExpansionCard(props: Props) {
|
|||||||
type='number'
|
type='number'
|
||||||
value={additionalSeats}
|
value={additionalSeats}
|
||||||
onChange={handleNewSeatsInputChange}
|
onChange={handleNewSeatsInputChange}
|
||||||
error={invalidAdditionalSeats}
|
|
||||||
disabled={maxAdditionalSeats === 0}
|
disabled={maxAdditionalSeats === 0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='SelfHostedExpansionRHSCard__AddSeatsWarning'>
|
<div className='SelfHostedExpansionRHSCard__AddSeatsWarning'>
|
||||||
{invalidAdditionalSeats && !overMaxSeats &&
|
{invalidAdditionalSeats && !overMaxSeats && isNaN(additionalSeats) &&
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='self_hosted_expansion_rhs_card_must_add_seats_warning'
|
id='self_hosted_expansion_rhs_card_must_add_seats_warning'
|
||||||
defaultMessage='{warningIcon} You must add a seat to continue'
|
defaultMessage='{warningIcon} You must add a seat to continue'
|
||||||
@@ -155,6 +154,16 @@ export default function SelfHostedExpansionCard(props: Props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
{invalidAdditionalSeats && additionalSeats < props.minimumSeats &&
|
||||||
|
<FormattedMessage
|
||||||
|
id='self_hosted_expansion_rhs_card_must_purchase_enough_seats'
|
||||||
|
defaultMessage='{warningIcon} You must purchase at least {minimumSeats} seats to be compliant with your license'
|
||||||
|
values={{
|
||||||
|
warningIcon: <WarningIcon additionalClassName={'SelfHostedExpansionRHSCard__warning'}/>,
|
||||||
|
minimumSeats: props.minimumSeats
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
{overMaxSeats && maxAdditionalSeats > 0 &&
|
{overMaxSeats && maxAdditionalSeats > 0 &&
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='self_hosted_expansion_rhs_card_maximum_seats_warning'
|
id='self_hosted_expansion_rhs_card_maximum_seats_warning'
|
||||||
@@ -203,7 +212,7 @@ export default function SelfHostedExpansionCard(props: Props) {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className='btn btn-primary SelfHostedExpansionRHSCard__CompletePurchaseButton'
|
className='btn btn-primary SelfHostedExpansionRHSCard__CompletePurchaseButton'
|
||||||
disabled={!props.canSubmit || maxAdditionalSeats === 0}
|
disabled={!props.canSubmit || maxAdditionalSeats === 0 || invalidAdditionalSeats}
|
||||||
onClick={props.submit}
|
onClick={props.submit}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|||||||
@@ -175,12 +175,13 @@ export default function SelfHostedExpansionModal() {
|
|||||||
const licensedSeats = parseInt(license.Users, 10);
|
const licensedSeats = parseInt(license.Users, 10);
|
||||||
const currentPlan = license.SkuName;
|
const currentPlan = license.SkuName;
|
||||||
const activeUsers = useSelector(getFilteredUsersStats)?.total_users_count || 0;
|
const activeUsers = useSelector(getFilteredUsersStats)?.total_users_count || 0;
|
||||||
const [additionalSeats, setAdditionalSeats] = useState(activeUsers <= licensedSeats ? 1 : activeUsers - licensedSeats);
|
const [minimumSeats] = useState(activeUsers <= licensedSeats ? 1 : activeUsers - licensedSeats);
|
||||||
|
const [requestedSeats, setRequestedSeats] = useState(minimumSeats)
|
||||||
|
|
||||||
const [stripeLoadHint, setStripeLoadHint] = useState(Math.random());
|
const [stripeLoadHint, setStripeLoadHint] = useState(Math.random());
|
||||||
const stripeRef = useLoadStripe(stripeLoadHint);
|
const stripeRef = useLoadStripe(stripeLoadHint);
|
||||||
|
|
||||||
const initialState = makeInitialState(additionalSeats);
|
const initialState = makeInitialState(requestedSeats);
|
||||||
const [formState, setFormState] = useState<FormState>(initialState);
|
const [formState, setFormState] = useState<FormState>(initialState);
|
||||||
const [show] = useState(true);
|
const [show] = useState(true);
|
||||||
const canRetry = formState.error !== '422';
|
const canRetry = formState.error !== '422';
|
||||||
@@ -492,12 +493,12 @@ export default function SelfHostedExpansionModal() {
|
|||||||
<SelfHostedExpansionCard
|
<SelfHostedExpansionCard
|
||||||
updateSeats={(seats: number) => {
|
updateSeats={(seats: number) => {
|
||||||
setFormState({...formState, seats});
|
setFormState({...formState, seats});
|
||||||
setAdditionalSeats(seats);
|
setRequestedSeats(seats);
|
||||||
}}
|
}}
|
||||||
canSubmit={canSubmitForm}
|
canSubmit={canSubmitForm}
|
||||||
submit={submit}
|
submit={submit}
|
||||||
licensedSeats={licensedSeats}
|
licensedSeats={licensedSeats}
|
||||||
initialSeats={additionalSeats}
|
minimumSeats={minimumSeats}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user