diff --git a/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.test.ts b/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.test.ts index fffed9a4c1..834e181735 100644 --- a/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.test.ts +++ b/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.test.ts @@ -190,4 +190,35 @@ describe('CommunityPlusEnrollmentModal', () => { await userEvent.click(skipButton); expect(consoleErrorSpy).not.toHaveBeenCalled(); }); + + it('should prevent multiple submissions', async () => { + const closeCallbackSpy = vi.fn(); + const usageStore = mockedStore(useUsageStore); + + usageStore.registerCommunityEdition.mockImplementation( + async () => + await new Promise((resolve) => + setTimeout(() => resolve({ title: 'Title', text: 'Text' }), 100), + ), + ); + + const props = { + modalName: COMMUNITY_PLUS_ENROLLMENT_MODAL, + data: { + closeCallback: closeCallbackSpy, + }, + }; + + const { getByRole } = renderComponent({ props }); + const emailInput = getByRole('textbox'); + expect(emailInput).toBeVisible(); + + await userEvent.type(emailInput, 'test@ema.il'); + await userEvent.keyboard('{Enter}'); + await userEvent.keyboard('{Enter}'); + + expect(getByRole('button', { name: buttonLabel })).toBeDisabled(); + expect(usageStore.registerCommunityEdition).toHaveBeenCalledWith('test@ema.il'); + expect(usageStore.registerCommunityEdition).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.vue b/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.vue index 70aa1455cd..3aaa62d647 100644 --- a/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.vue +++ b/packages/frontend/editor-ui/src/components/CommunityPlusEnrollmentModal.vue @@ -25,6 +25,7 @@ const usageStore = useUsageStore(); const telemetry = useTelemetry(); const usersStore = useUsersStore(); +const isLoading = ref(false); const valid = ref(false); const email = ref(usersStore.currentUser?.email ?? ''); const validationRules = ref([{ name: 'email' }]); @@ -56,6 +57,11 @@ const closeModal = () => { }; const confirm = async () => { + if (!valid.value || isLoading.value) { + return; + } + + isLoading.value = true; try { const { title, text } = await usageStore.registerCommunityEdition(email.value); closeModal(); @@ -71,6 +77,8 @@ const confirm = async () => { }); } catch (error) { toast.showError(error, i18n.baseText('communityPlusModal.error.title')); + } finally { + isLoading.value = false; } }; @@ -134,6 +142,7 @@ const confirm = async () => { :validation-rules="validationRules" :validators="validators" @validate="valid = $event" + @keyup.enter="confirm" /> @@ -147,10 +156,15 @@ const confirm = async () => {
- {{ - i18n.baseText('communityPlusModal.button.skip') - }} - + {{ i18n.baseText('communityPlusModal.button.skip') }} + {{ i18n.baseText('communityPlusModal.button.confirm') }}