diff --git a/static/app/views/settings/organizationIntegrations/integrationRequest/RequestIntegrationModal.tsx b/static/app/views/settings/organizationIntegrations/integrationRequest/RequestIntegrationModal.tsx index ee0d2c41c8e6cc..f4c764b22b253d 100644 --- a/static/app/views/settings/organizationIntegrations/integrationRequest/RequestIntegrationModal.tsx +++ b/static/app/views/settings/organizationIntegrations/integrationRequest/RequestIntegrationModal.tsx @@ -1,17 +1,17 @@ -import {Fragment, useState} from 'react'; import {useMutation} from '@tanstack/react-query'; +import {z} from 'zod'; -import {Button} from '@sentry/scraps/button'; +import {defaultFormOptions, useScrapsForm} from '@sentry/scraps/form'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import type {ModalRenderProps} from 'sentry/actionCreators/modal'; -import {TextareaField} from 'sentry/components/forms/fields/textareaField'; import {t} from 'sentry/locale'; import type {IntegrationType} from 'sentry/types/integrations'; import {trackIntegrationAnalytics} from 'sentry/utils/integrationUtil'; import {useApi} from 'sentry/utils/useApi'; import {useOrganization} from 'sentry/utils/useOrganization'; import {TextBlock} from 'sentry/views/settings/components/text/textBlock'; + type Props = { name: string; onSuccess: () => void; @@ -19,14 +19,16 @@ type Props = { type: IntegrationType; } & ModalRenderProps; +const schema = z.object({ + message: z.string(), +}); + /** * This modal serves as a non-owner's confirmation step before sending * organization owners an email requesting a new organization integration. It * lets the user attach an optional message to be included in the email. */ export function RequestIntegrationModal(props: Props) { - const [isSending, setIsSending] = useState(false); - const [message, setMessage] = useState(''); const organization = useOrganization(); const api = useApi({persistInFlight: true}); @@ -35,18 +37,16 @@ export function RequestIntegrationModal(props: Props) { const endpoint = `/organizations/${organization.slug}/integration-requests/`; const sendRequestMutation = useMutation({ - mutationFn: () => { - return api.requestPromise(endpoint, { + mutationFn: (data: z.infer) => + api.requestPromise(endpoint, { method: 'POST', data: { providerSlug: slug, providerType: type, - message, + message: data.message, }, - }); - }, + }), onMutate: () => { - setIsSending(true); trackIntegrationAnalytics('integrations.request_install', { integration_type: type, integration: slug, @@ -55,20 +55,23 @@ export function RequestIntegrationModal(props: Props) { }, onSuccess: () => { addSuccessMessage(t('Request successfully sent.')); - setIsSending(false); onSuccess(); closeModal(); }, onError: () => { - addErrorMessage('Error sending the request'); - setIsSending(false); + addErrorMessage(t('Error sending the request')); }, }); - const buttonText = isSending ? t('Sending Request') : t('Send Request'); + const form = useScrapsForm({ + ...defaultFormOptions, + defaultValues: {message: ''}, + validators: {onDynamic: schema}, + onSubmit: ({value}) => sendRequestMutation.mutateAsync(value).catch(() => {}), + }); return ( - +

{t('Request %s Installation', name)}

@@ -86,15 +89,17 @@ export function RequestIntegrationModal(props: Props) { name )} - + + {field => ( + + + + )} + {t( 'When you click “Send Request”, we’ll email your request to your organization’s owners. So just keep that in mind.' @@ -102,8 +107,8 @@ export function RequestIntegrationModal(props: Props) { - + ); }