Browse Source

feat(partnership): Replace sentry component with hook (#63067)

depends on: https://github.com/getsentry/getsentry/pull/12593
This component has a getsentry API call so moving it there and replacing
with a hook.
Athena Moghaddam 1 year ago
parent
commit
f73ccc38c8

+ 1 - 1
static/app/types/hooks.tsx

@@ -187,7 +187,7 @@ export type ComponentHooks = {
   'component:monitor-status-toggle': () => React.ComponentType<StatusToggleButtonProps>;
   'component:org-stats-banner': () => React.ComponentType<DashboardHeadersProps>;
   'component:organization-header': () => React.ComponentType<OrganizationHeaderProps>;
-  'component:partnership-agreement': React.ComponentType<PartnershipAgreementProps>,
+  'component:partnership-agreement': React.ComponentType<PartnershipAgreementProps>;
   'component:product-selection-availability': () => React.ComponentType<ProductSelectionAvailabilityProps>;
   'component:product-unavailable-cta': () => React.ComponentType<ProductUnavailableCTAProps>;
   'component:profiling-am1-or-mmx-upgrade': () => React.ComponentType<ProfilingAM1OrMMXUpgradeProps>;

+ 1 - 1
static/app/types/system.tsx

@@ -2,7 +2,7 @@ import {Theme} from '@emotion/react';
 import type {FocusTrap} from 'focus-trap';
 
 import type {exportedGlobals} from 'sentry/bootstrap/exportGlobals';
-import {ParntershipAgreementType} from 'sentry/views/partnershipAgreement';
+import {ParntershipAgreementType} from 'sentry/types/hooks';
 
 import type {User} from './user';
 

+ 27 - 11
static/app/views/app/index.spec.tsx

@@ -5,8 +5,18 @@ import {initializeOrg} from 'sentry-test/initializeOrg';
 import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import ConfigStore from 'sentry/stores/configStore';
+import HookStore from 'sentry/stores/hookStore';
 import App from 'sentry/views/app';
 
+function HookWrapper(props) {
+  return (
+    <div data-test-id="hook-wrapper">
+      {props.children}
+      <span>{JSON.stringify(props?.organization ?? {}, null, 2)}</span>
+    </div>
+  );
+}
+
 describe('App', function () {
   const configState = ConfigStore.getState();
   const {routerProps} = initializeOrg();
@@ -15,6 +25,8 @@ describe('App', function () {
     ConfigStore.init();
     ConfigStore.loadInitialData(configState);
 
+    HookStore.init();
+
     MockApiClient.addMockResponse({
       url: '/organizations/',
       body: [OrganizationFixture({slug: 'billy-org', name: 'billy org'})],
@@ -66,25 +78,29 @@ describe('App', function () {
     user.flags.newsletter_consent_prompt = false;
   });
 
-  it('renders PartnershipAgreement', async function () {
+  it('renders PartnershipAgreement', function () {
     ConfigStore.set('partnershipAgreementPrompt', {partnerDisplayName: 'Foo', agreements:['standard', 'partner_presence']});
+    HookStore.add(
+      'component:partnership-agreement',
+      () =>
+      <HookWrapper key={0}/>
+    );
     render(
       <App {...routerProps}>
         <div>placeholder content</div>
       </App>
     );
-
-    expect(
-      await screen.findByText(/This organization is created in partnership with Foo/)
-    ).toBeInTheDocument();
-    expect(
-      await screen.findByText(/and are aware of the partner's presence in the organization as a manager./)
-    ).toBeInTheDocument();
-    expect(screen.queryByText('placeholder content')).not.toBeInTheDocument();
+    expect(HookStore.get('component:partnership-agreement')).toHaveLength(1);
+    expect(screen.getByTestId('hook-wrapper')).toBeInTheDocument();
   });
 
-  it('does not render PartnerAgreement for non-partnered orgs', async function () {
+  it('does not render PartnerAgreement for non-partnered orgs', function () {
     ConfigStore.set('partnershipAgreementPrompt', null);
+    HookStore.add(
+      'component:partnership-agreement',
+      () =>
+      <HookWrapper key={0}/>
+    );
     render(
       <App {...routerProps}>
         <div>placeholder content</div>
@@ -92,7 +108,7 @@ describe('App', function () {
     );
 
     expect(screen.getByText('placeholder content')).toBeInTheDocument();
-    expect(await screen.queryByText(/This organization is created in partnership/)).not.toBeInTheDocument();
+    expect(screen.queryByTestId('hook-wrapper')).not.toBeInTheDocument();
   });
 
   it('renders InstallWizard for self-hosted', async function () {

+ 5 - 4
static/app/views/app/index.tsx

@@ -12,6 +12,7 @@ import {fetchOrganizations} from 'sentry/actionCreators/organizations';
 import {initApiClientErrorHandling} from 'sentry/api';
 import ErrorBoundary from 'sentry/components/errorBoundary';
 import GlobalModal from 'sentry/components/globalModal';
+import Hook from 'sentry/components/hook';
 import Indicators from 'sentry/components/indicators';
 import {DEPLOY_PREVIEW_CONFIG, EXPERIMENTAL_SPA} from 'sentry/constants';
 import AlertStore from 'sentry/stores/alertStore';
@@ -36,7 +37,6 @@ const InstallWizard: React.FC<InstallWizardProps> = lazy(
   () => import('sentry/views/admin/installWizard')
 );
 const NewsletterConsent = lazy(() => import('sentry/views/newsletterConsent'));
-const PartnershipAgreement = lazy(() => import('sentry/views/partnershipAgreement'));
 
 /**
  * App is the root level container for all uathenticated routes.
@@ -179,11 +179,12 @@ function App({children, params}: Props) {
     if (partnershipAgreementPrompt) {
       return (
         <Suspense fallback={null}>
-          <PartnershipAgreement
+          <Hook
+            name="component:partnership-agreement"
             partnerDisplayName={partnershipAgreementPrompt.partnerDisplayName}
             agreements={partnershipAgreementPrompt.agreements}
-            onSubmitSuccess={() => ConfigStore.set('partnershipAgreementPrompt', null)
-          } />
+            onSubmitSuccess={() => ConfigStore.set('partnershipAgreementPrompt', null)}
+          />
         </Suspense>
       );
     }

+ 0 - 34
static/app/views/partnershipAgreement/index.tsx

@@ -1,34 +0,0 @@
-import Form from 'sentry/components/forms/form';
-import ExternalLink from 'sentry/components/links/externalLink';
-import NarrowLayout from 'sentry/components/narrowLayout';
-import {tct} from 'sentry/locale';
-
-export type ParntershipAgreementType = 'standard' | 'partner_presence';
-
-type Props = {
-  agreements: Array<ParntershipAgreementType>,
-  partnerDisplayName: string,
-  onSubmitSuccess?: () => void;
-};
-
-export default function PartnershipAgreement({partnerDisplayName, agreements, onSubmitSuccess}: Props) {
-  const tos = <ExternalLink href='https://sentry.io/terms/'>terms of service</ExternalLink>;
-  const privacyPolicy = <ExternalLink href='https://sentry.io/privacy/'>privacy policy</ExternalLink>;
-  // TODO @athena: Add API call to the form
-  return (
-    <NarrowLayout>
-      <Form submitLabel="Continue" onSubmitSuccess={onSubmitSuccess}>
-        {agreements.includes('partner_presence')
-          ? tct(
-              "This organization is created in partnership with [partnerDisplayName]. By pressing continue, you acknowledge that you have agreed to Sentry's [tos] and [privacyPolicy] through the partner's application and are aware of the partner's presence in the organization as a manager.",
-              {partnerDisplayName, tos, privacyPolicy}
-            )
-          : tct(
-              "This organization is created in partnership with [partnerDisplayName]. By pressing continue, you acknowledge that you have agreed to Sentry's [tos] and [privacyPolicy] through the partner's application.",
-              {partnerDisplayName, tos, privacyPolicy}
-            )
-        }
-      </Form>
-    </NarrowLayout>
-  );
-}