Browse Source

ref(js): Convert OrganizationDetails* to functional components (#28921)

Evan Purkhiser 3 years ago
parent
commit
79e143d5da

+ 121 - 0
static/app/views/organizationDetails/body.tsx

@@ -0,0 +1,121 @@
+import {Fragment, useState} from 'react';
+
+import AlertActions from 'app/actions/alertActions';
+import Alert from 'app/components/alert';
+import Button from 'app/components/button';
+import ErrorBoundary from 'app/components/errorBoundary';
+import Footer from 'app/components/footer';
+import {Body, Main} from 'app/components/layouts/thirds';
+import {IconWarning} from 'app/icons';
+import {t, tct} from 'app/locale';
+import {Organization} from 'app/types';
+import useApi from 'app/utils/useApi';
+import withOrganization from 'app/utils/withOrganization';
+
+type Props = {
+  organization: Organization;
+  children?: React.ReactNode;
+};
+
+function DeletionInProgress({organization}: Props) {
+  return (
+    <Body>
+      <Main>
+        <Alert type="warning" icon={<IconWarning />}>
+          {tct(
+            'The [organization] organization is currently in the process of being deleted from Sentry.',
+            {
+              organization: <strong>{organization.slug}</strong>,
+            }
+          )}
+        </Alert>
+      </Main>
+    </Body>
+  );
+}
+
+function DeletionPending({organization}: Props) {
+  const api = useApi();
+  const [isRestoring, setIsRestoring] = useState(false);
+
+  const onRestore = async () => {
+    setIsRestoring(true);
+
+    try {
+      await api.requestPromise(`/organizations/${organization.slug}/`, {
+        method: 'PUT',
+        data: {cancelDeletion: true},
+      });
+      window.location.reload();
+    } catch {
+      setIsRestoring(false);
+      AlertActions.addAlert({
+        message:
+          'We were unable to restore this organization. Please try again or contact support.',
+        type: 'error',
+      });
+    }
+  };
+
+  return (
+    <Body>
+      <Main>
+        <h3>{t('Deletion Scheduled')}</h3>
+        <p>
+          {tct('The [organization] organization is currently scheduled for deletion.', {
+            organization: <strong>{organization.slug}</strong>,
+          })}
+        </p>
+
+        {organization.access.includes('org:admin') ? (
+          <div>
+            <p>
+              {t(
+                'Would you like to cancel this process and restore the organization back to the original state?'
+              )}
+            </p>
+            <p>
+              <Button priority="primary" onClick={onRestore} disabled={isRestoring}>
+                {t('Restore Organization')}
+              </Button>
+            </p>
+          </div>
+        ) : (
+          <p>
+            {t(
+              'If this is a mistake, contact an organization owner and ask them to restore this organization.'
+            )}
+          </p>
+        )}
+        <p>
+          <small>
+            {t(
+              "Note: Restoration is available until the process begins. Once it does, there's no recovering the data that has been removed."
+            )}
+          </small>
+        </p>
+      </Main>
+    </Body>
+  );
+}
+
+function OrganizationDetailsBody({children, organization}: Props) {
+  const status = organization?.status?.id;
+
+  if (status === 'pending_deletion') {
+    return <DeletionPending organization={organization} />;
+  }
+
+  if (status === 'deletion_in_progress') {
+    return <DeletionInProgress organization={organization} />;
+  }
+
+  return (
+    <Fragment>
+      <ErrorBoundary>{children}</ErrorBoundary>
+      <Footer />
+    </Fragment>
+  );
+}
+
+export default withOrganization(OrganizationDetailsBody);

+ 12 - 166
static/app/views/organizationDetails/index.tsx

@@ -1,177 +1,23 @@
-import {Component, Fragment} from 'react';
+import {useEffect} from 'react';
 import {RouteComponentProps} from 'react-router';
 
 import {switchOrganization} from 'app/actionCreators/organizations';
-import AlertActions from 'app/actions/alertActions';
-import {Client} from 'app/api';
-import Alert from 'app/components/alert';
-import Button from 'app/components/button';
-import ErrorBoundary from 'app/components/errorBoundary';
-import Footer from 'app/components/footer';
-import {Body, Main} from 'app/components/layouts/thirds';
-import {IconWarning} from 'app/icons';
-import {t, tct} from 'app/locale';
-import {Organization} from 'app/types';
-import withOrganization from 'app/utils/withOrganization';
 import OrganizationContextContainer from 'app/views/organizationContext';
 
-type InProgressProps = {
-  organization: Organization;
-};
+import Body from './body';
 
-function DeletionInProgress({organization}: InProgressProps) {
-  return (
-    <Body>
-      <Main>
-        <Alert type="warning" icon={<IconWarning />}>
-          {tct(
-            'The [organization] organization is currently in the process of being deleted from Sentry.',
-            {
-              organization: <strong>{organization.slug}</strong>,
-            }
-          )}
-        </Alert>
-      </Main>
-    </Body>
-  );
-}
-
-type PendingProps = {
-  organization: Organization;
-};
-
-type PendingState = {
-  submitInProgress: boolean;
-};
+type Props = RouteComponentProps<{orgId: string}, {}> &
+  Partial<React.ComponentProps<typeof OrganizationContextContainer>>;
 
-class DeletionPending extends Component<PendingProps, PendingState> {
-  state: PendingState = {submitInProgress: false};
-
-  componentWillUnmount() {
-    this.api.clear();
-  }
-
-  api = new Client();
-
-  onRestore = () => {
-    if (this.state.submitInProgress) {
-      return;
-    }
-    this.setState({submitInProgress: true});
-    this.api.request(`/organizations/${this.props.organization.slug}/`, {
-      method: 'PUT',
-      data: {cancelDeletion: true},
-      success: () => {
-        window.location.reload();
-      },
-      error: () => {
-        AlertActions.addAlert({
-          message:
-            'We were unable to restore this organization. Please try again or contact support.',
-          type: 'error',
-        });
-        this.setState({submitInProgress: false});
-      },
-    });
-  };
-
-  render() {
-    const {organization} = this.props;
-    const access = new Set(organization.access);
-    return (
-      <Body>
-        <Main>
-          <h3>{t('Deletion Scheduled')}</h3>
-          <p>
-            {tct('The [organization] organization is currently scheduled for deletion.', {
-              organization: <strong>{organization.slug}</strong>,
-            })}
-          </p>
-
-          {access.has('org:admin') ? (
-            <div>
-              <p>
-                {t(
-                  'Would you like to cancel this process and restore the organization back to the original state?'
-                )}
-              </p>
-              <p>
-                <Button
-                  priority="primary"
-                  onClick={this.onRestore}
-                  disabled={this.state.submitInProgress}
-                >
-                  {t('Restore Organization')}
-                </Button>
-              </p>
-            </div>
-          ) : (
-            <p>
-              {t(
-                'If this is a mistake, contact an organization owner and ask them to restore this organization.'
-              )}
-            </p>
-          )}
-          <p>
-            <small>
-              {t(
-                "Note: Restoration is available until the process begins. Once it does, there's no recovering the data that has been removed."
-              )}
-            </small>
-          </p>
-        </Main>
-      </Body>
-    );
-  }
-}
-
-type OrganizationDetailsProps = {
-  organization?: Organization;
-  children?: React.ReactNode;
-};
-
-const OrganizationDetailsBody = withOrganization(function OrganizationDetailsBody({
-  children,
-  organization,
-}: OrganizationDetailsProps) {
-  const status = organization?.status?.id;
-
-  if (organization && status === 'pending_deletion') {
-    return <DeletionPending organization={organization} />;
-  }
-
-  if (organization && status === 'deletion_in_progress') {
-    return <DeletionInProgress organization={organization} />;
-  }
+function OrganizationDetails({children, ...props}: Props) {
+  // Switch organizations when the orgId changes
+  useEffect(() => void switchOrganization(), [props.params.orgId]);
 
   return (
-    <Fragment>
-      <ErrorBoundary>{children}</ErrorBoundary>
-      <Footer />
-    </Fragment>
+    <OrganizationContextContainer includeSidebar useLastOrganization {...props}>
+      <Body>{children}</Body>
+    </OrganizationContextContainer>
   );
-});
-
-type Props = RouteComponentProps<{orgId: string}, {}>;
-
-export default class OrganizationDetails extends Component<Props> {
-  componentDidUpdate(prevProps: Props) {
-    if (
-      prevProps.params &&
-      this.props.params &&
-      prevProps.params.orgId !== this.props.params.orgId
-    ) {
-      switchOrganization();
-    }
-  }
-
-  render() {
-    return (
-      <OrganizationContextContainer includeSidebar useLastOrganization {...this.props}>
-        <OrganizationDetailsBody {...this.props}>
-          {this.props.children}
-        </OrganizationDetailsBody>
-      </OrganizationContextContainer>
-    );
-  }
 }
+
+export default OrganizationDetails;