From a7588b76001ed2690063aabbe9edd60778cc27b9 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:57:24 +0200 Subject: [PATCH] feat($env): api integration --- .../OrderEnvironments.test.tsx | 42 ++++++++++++++++ .../OrderEnvironments/OrderEnvironments.tsx | 31 ++++++++++-- .../OrderEnvironmentsDialog.tsx | 48 ++++++++++++------- 3 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.test.tsx diff --git a/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.test.tsx b/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.test.tsx new file mode 100644 index 000000000000..49e7d9513192 --- /dev/null +++ b/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.test.tsx @@ -0,0 +1,42 @@ +import { screen, fireEvent, waitFor } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { OrderEnvironments } from './OrderEnvironments'; +import { testServerRoute, testServerSetup } from 'utils/testServer'; + +const server = testServerSetup(); + +const setupServerRoutes = (changeRequestsEnabled = true) => { + testServerRoute(server, '/api/admin/ui-config', { + environment: 'Pro', + flags: { + purchaseAdditionalEnvironments: true, + }, + }); +}; + +describe('OrderEnvironmentsDialog Component', () => { + test('should show error if environment name is empty', async () => { + setupServerRoutes(); + render(); + + await waitFor(async () => { + const openDialogButton = await screen.queryByRole('button', { + name: /view pricing/i, + }); + expect(openDialogButton).toBeInTheDocument(); + fireEvent.click(openDialogButton!); + }); + + const checkbox = screen.getByRole('checkbox', { + name: /i understand adding environments/i, + }); + fireEvent.click(checkbox); + + const submitButton = screen.getByRole('button', { name: /order/i }); + fireEvent.click(submitButton); + + expect( + screen.getByText(/environment name is required/i), + ).toBeInTheDocument(); + }); +}); diff --git a/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.tsx b/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.tsx index c03cc1234209..5111b72e99f7 100644 --- a/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.tsx +++ b/frontend/src/component/environments/EnvironmentTable/OrderEnvironments/OrderEnvironments.tsx @@ -4,6 +4,8 @@ import { useUiFlag } from 'hooks/useUiFlag'; import { PurchasableFeature } from './PurchasableFeature/PurchasableFeature'; import { OrderEnvironmentsDialog } from './OrderEnvironmentsDialog/OrderEnvironmentsDialog'; import { OrderEnvironmentsConfirmation } from './OrderEnvironmentsConfirmation/OrderEnvironmentsConfirmation'; +import { useFormErrors } from 'hooks/useFormErrors'; +import useToast from 'hooks/useToast'; type OrderEnvironmentsProps = {}; @@ -17,18 +19,36 @@ export const OrderEnvironments: FC = () => { const isPurchaseAdditionalEnvironmentsEnabled = useUiFlag( 'purchaseAdditionalEnvironments', ); + const errors = useFormErrors(); + const { setToastData, setToastApiError } = useToast(); if (!isPro() || !isPurchaseAdditionalEnvironmentsEnabled) { return null; } const onSubmit = (environments: string[]) => { - setPurchaseDialogOpen(false); - // TODO: API call - setConfirmationState({ - isOpen: true, - environmentsCount: environments.length, + let hasErrors = false; + environments.forEach((environment, index) => { + const field = `environment-${index}`; + if (environment.trim() === '') { + errors.setFormError(field, 'Environment name is required'); + hasErrors = true; + } else { + errors.removeFormError(field); + } }); + + if (hasErrors) { + return; + } else { + // TODO: API call + + setPurchaseDialogOpen(false); + setConfirmationState({ + isOpen: true, + environmentsCount: environments.length, + }); + } }; return ( @@ -42,6 +62,7 @@ export const OrderEnvironments: FC = () => { open={purchaseDialogOpen} onClose={() => setPurchaseDialogOpen(false)} onSubmit={onSubmit} + errors={errors} /> void; onSubmit: (environments: string[]) => void; + errors?: IFormErrors; }; const StyledDialog = styled(Dialog)(({ theme }) => ({ @@ -74,10 +76,13 @@ export const OrderEnvironmentsDialog: FC = ({ open, onClose, onSubmit, + errors, }) => { const [selectedOption, setSelectedOption] = useState(OPTIONS[0]); const [costCheckboxChecked, setCostCheckboxChecked] = useState(false); - const [environmentNames, setEnvironmentNames] = useState([]); + const [environmentNames, setEnvironmentNames] = useState(['']); + + console.log({ environmentNames }); return ( @@ -133,7 +138,10 @@ export const OrderEnvironmentsDialog: FC = ({ const value = Number.parseInt(option, 10); setSelectedOption(value); setEnvironmentNames((names) => - names.slice(0, value), + [...names, ...Array(value).fill('')].slice( + 0, + value, + ), ); }} /> @@ -143,20 +151,28 @@ export const OrderEnvironmentsDialog: FC = ({ How would you like the environment {selectedOption > 1 ? 's' : ''} to be named? - {[...Array(selectedOption)].map((_, i) => ( - { - setEnvironmentNames((names) => { - const newValues = [...names]; - newValues[i] = event.target.value; - return newValues; - }); - }} - /> - ))} + {[...Array(selectedOption)].map((_, i) => { + const error = errors?.getFormError( + `environment-${i}`, + ); + + return ( + { + setEnvironmentNames((names) => { + const newValues = [...names]; + newValues[i] = event.target.value; + return newValues; + }); + }} + error={Boolean(error)} + errorText={error} + /> + ); + })}