diff --git a/webapp/channels/src/components/seats_calculator/index.tsx b/webapp/channels/src/components/seats_calculator/index.tsx index fe2b9259a2..a38d09b70d 100644 --- a/webapp/channels/src/components/seats_calculator/index.tsx +++ b/webapp/channels/src/components/seats_calculator/index.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {useEffect} from 'react'; import {useIntl, FormattedMessage, FormattedNumber} from 'react-intl'; import {InformationOutlineIcon} from '@mattermost/compass-icons/components'; @@ -41,6 +41,12 @@ export const errorInvalidNumber = ( defaultMessage='Enter a valid number of seats' /> ); +export const errorMinSeats = ( + +); function validateSeats(seats: string, annualPricePerSeat: number, minSeats: number, cloud: boolean): Seats { if (seats === '') { @@ -58,6 +64,13 @@ function validateSeats(seats: string, annualPricePerSeat: number, minSeats: numb }; } + if (seatsNumber < 10) { + return { + quantity: seats, + error: errorMinSeats, + }; + } + const maxSeats = calculateMaxUsers(annualPricePerSeat); const tooFewUsersErrorMessage = ( { + props.onChange(validateSeats(props.seats.quantity, annualPricePerSeat, props.existingUsers, props.isCloud)); + }, []); + const maxSeats = calculateMaxUsers(annualPricePerSeat); const total = '$' + intl.formatNumber((parseFloat(props.seats.quantity) || 0) * annualPricePerSeat, {maximumFractionDigits: 2}); const userCountTooltip = ( diff --git a/webapp/channels/src/components/seats_calculator/seats_calculator.scss b/webapp/channels/src/components/seats_calculator/seats_calculator.scss index 18dd6699a6..80add6f083 100644 --- a/webapp/channels/src/components/seats_calculator/seats_calculator.scss +++ b/webapp/channels/src/components/seats_calculator/seats_calculator.scss @@ -2,6 +2,10 @@ padding: 14px 0; font-size: 14px; + .Input___customMessage.Input___error { + line-height: 14px; + } + &__seats-item { position: relative; display: flex; diff --git a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx index 81437b3d7a..c8d568206b 100644 --- a/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchase_modal/index.test.tsx @@ -69,7 +69,7 @@ const mockCreatedIntent = SelfHostedSignupProgress.CREATED_INTENT; const mockCreatedLicense = SelfHostedSignupProgress.CREATED_LICENSE; const failOrg = 'failorg'; -const existingUsers = 10; +const existingUsers = 11; jest.mock('mattermost-redux/client', () => { const original = jest.requireActual('mattermost-redux/client'); @@ -275,7 +275,17 @@ describe('SelfHostedPurchaseModal', () => { const tooFewSeats = existingUsers - 1; fireEvent.change(screen.getByTestId('selfHostedPurchaseSeatsInput'), valueEvent(tooFewSeats.toString())); expect(screen.getByText('Upgrade')).toBeDisabled(); - screen.getByText('Your workspace currently has 10 users', {exact: false}); + screen.getByText('Your workspace currently has 11 users', {exact: false}); + }); + + it('Minimum of 10 seats is required for sign up', () => { + renderWithIntlAndStore(
, initialState); + fillForm(defaultSuccessForm); + + const tooFewSeats = 9; + fireEvent.change(screen.getByTestId('selfHostedPurchaseSeatsInput'), valueEvent(tooFewSeats.toString())); + expect(screen.getByText('Upgrade')).toBeDisabled(); + screen.getByText('Minimum of 10 seats required', {exact: false}); }); it('happy path submit shows success screen', async () => { diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 269e9af208..3434e71dd2 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -3068,6 +3068,7 @@ "cloud_delinquency.post_downgrade_banner.title": "Update your billing information now to re-activate paid features.", "cloud_signup.signup_consequences": "Your credit card will be charged today. See how billing works.", "cloud_subscribe.contact_support": "Compare plans", + "cloud_upgrade.error_min_seats": "Minimum of 10 seats required", "cloud.fetch_error": "Error fetching billing data. Please try again later.", "cloud.fetch_error.retry": "Retry", "cloud.invoice_pdf_preview.download": "Download this page for your records", diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index 091eb5aff6..87fc6be03a 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -1983,6 +1983,7 @@ export const Constants = { CHANNEL_HEADER_BUTTON_DISABLE_TIMEOUT: 1000, FIRST_ADMIN_ROLE: 'first_admin', MAX_PURCHASE_SEATS: 1000000, + MIN_PURCHASE_SEATS: 10, }; export const ValidationErrors = {