diff --git a/static/gsAdmin/components/forkCustomer.tsx b/static/gsAdmin/components/forkCustomer.tsx index b946357a77ef06..3bae9e85f284d3 100644 --- a/static/gsAdmin/components/forkCustomer.tsx +++ b/static/gsAdmin/components/forkCustomer.tsx @@ -1,14 +1,16 @@ -import {Component, Fragment} from 'react'; +import {Fragment, useEffect, useRef, useState} from 'react'; -import {Client} from 'sentry/api'; import SelectField from 'sentry/components/forms/fields/selectField'; import type {Organization} from 'sentry/types/organization'; -import {browserHistory} from 'sentry/utils/browserHistory'; +import {useMutation} from 'sentry/utils/queryClient'; import { getRegionChoices, getRegionDataFromOrganization, getRegions, } from 'sentry/utils/regions'; +import type RequestError from 'sentry/utils/requestError/requestError'; +import useApi from 'sentry/utils/useApi'; +import {useNavigate} from 'sentry/utils/useNavigate'; import type { AdminConfirmParams, @@ -19,69 +21,68 @@ type Props = AdminConfirmRenderProps & { organization: Organization; }; -type State = { - regionUrl: string; -}; - /** * Rendered as part of a openAdminConfirmModal call */ -class ForkCustomerAction extends Component { - state: State = { - regionUrl: '', - }; +export default function ForkCustomerAction({ + organization, + onConfirm, + setConfirmCallback, +}: Props) { + // TODO: We should make sure that `setConfirmCallback` is a stable function + // before passing it in here. But because it's not memoized right now, we + // need to store it in a ref between renders. + const onConfirmRef = useRef(setConfirmCallback); - componentDidMount() { - this.props.setConfirmCallback(this.handleConfirm); - } + const [regionUrl, setRegionUrl] = useState(''); + const api = useApi({persistInFlight: true}); + const navigate = useNavigate(); - handleConfirm = async (params: AdminConfirmParams) => { - const api = new Client({headers: {Accept: 'application/json; charset=utf-8'}}); - const {organization} = this.props; - const {regionUrl} = this.state; - const regions = getRegions(); - const region = regions.find(r => r.url === regionUrl); - - try { - const response = await api.requestPromise( - `/organizations/${organization.slug}/fork/`, - { - method: 'POST', - host: region?.url, - } - ); + const {mutate} = useMutation({ + mutationFn: () => { + const regions = getRegions(); + const region = regions.find(r => r.url === regionUrl); - browserHistory.push(`/_admin/relocations/${region?.name}/${response.uuid}/`); - this.props.onConfirm?.({regionUrl, ...params}); - } catch (error) { + return api.requestPromise(`/organizations/${organization.slug}/fork/`, { + method: 'POST', + host: region?.url, + }); + }, + onSuccess: (response, params) => { + const regions = getRegions(); + const region = regions.find(r => r.url === regionUrl); + navigate(`/_admin/relocations/${region?.name}/${response.uuid}/`); + onConfirm?.({regionUrl, ...params}); + }, + onError: (error: RequestError, _params) => { if (error.responseJSON) { - this.props.onConfirm?.({error}); + onConfirm?.({error}); } - } - }; + }, + }); - render() { - const {organization} = this.props; - const currentRegionData = getRegionDataFromOrganization(organization); - const regionChoices = getRegionChoices(currentRegionData ? [currentRegionData] : []); - return ( - - SAAS relocation job, but the source organization will not be affected." - } - choices={regionChoices} - inline={false} - stacked - required - value={this.state.regionUrl} - onChange={(val: any) => this.setState({regionUrl: val})} - /> - - ); - } -} + useEffect(() => { + onConfirmRef.current(mutate); + }, [mutate]); + + const currentRegionData = getRegionDataFromOrganization(organization); + const regionChoices = getRegionChoices(currentRegionData ? [currentRegionData] : []); -export default ForkCustomerAction; + return ( + + SAAS relocation job, but the source organization will not be affected." + } + choices={regionChoices} + inline={false} + stacked + required + value={regionUrl} + onChange={setRegionUrl} + /> + + ); +}