tryBusinessSidebarItem.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import {Component} from 'react';
  2. import {prefersStackedNav} from 'sentry/components/nav/prefersStackedNav';
  3. import {
  4. SidebarButton,
  5. SidebarItem as NavSidebarItem,
  6. SidebarItemUnreadIndicator,
  7. } from 'sentry/components/nav/primary/components';
  8. import SidebarItem from 'sentry/components/sidebar/sidebarItem';
  9. import {IconBusiness} from 'sentry/icons';
  10. import {t} from 'sentry/locale';
  11. import type {Hooks} from 'sentry/types/hooks';
  12. import type {Organization} from 'sentry/types/organization';
  13. import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
  14. import {openUpsellModal} from 'getsentry/actionCreators/modal';
  15. import TrialStartedSidebarItem from 'getsentry/components/trialStartedSidebarItem';
  16. import withSubscription from 'getsentry/components/withSubscription';
  17. import type {Subscription} from 'getsentry/types';
  18. import {hasPerformance, isBizPlanFamily} from 'getsentry/utils/billing';
  19. const AUTO_OPEN_HASH = '#try-business';
  20. type Props = Parameters<Hooks['sidebar:bottom-items']>[0] & {
  21. organization: Organization;
  22. subscription: Subscription;
  23. };
  24. const TRY_BUSINESS_SEEN_KEY = `sidebar-new-seen:try-business-v1`;
  25. function TryBusinessNavigationItem({
  26. subscription,
  27. onClick,
  28. }: {
  29. label: string;
  30. onClick: () => void;
  31. subscription: Subscription;
  32. }) {
  33. const [tryBusinessSeen, setTryBusinessSeen] = useLocalStorageState(
  34. TRY_BUSINESS_SEEN_KEY,
  35. false
  36. );
  37. const isNew = !subscription.isTrial && subscription.canTrial;
  38. const showIsNew = isNew && !tryBusinessSeen;
  39. return (
  40. <NavSidebarItem>
  41. <SidebarButton
  42. label={t('Try Business')}
  43. onClick={() => {
  44. setTryBusinessSeen(true);
  45. onClick();
  46. }}
  47. analyticsKey="try-business"
  48. >
  49. <IconBusiness size="md" />
  50. {showIsNew && <SidebarItemUnreadIndicator />}
  51. </SidebarButton>
  52. </NavSidebarItem>
  53. );
  54. }
  55. class TryBusinessSidebarItem extends Component<Props> {
  56. componentDidMount() {
  57. const search = document.location.search;
  58. const params = ['utm_source', 'utm_medium', 'utm_term'];
  59. const source = search
  60. ?.split('&')
  61. .map(param => param.split('='))
  62. .filter(param => params.includes(param[0]!))
  63. .map(param => param[1])
  64. .join('_');
  65. if (document.location.hash === AUTO_OPEN_HASH) {
  66. openUpsellModal({
  67. organization: this.props.organization,
  68. source: source || 'direct',
  69. });
  70. }
  71. }
  72. openModal = () => {
  73. const {organization} = this.props;
  74. openUpsellModal({organization, source: 'try-business-sidebar'});
  75. // force an update so we can re-render the sidebar item with the updated localstorage
  76. // where the new will be gone and add a delay since the modal takes time to open
  77. setTimeout(() => this.forceUpdate(), 200);
  78. };
  79. get labelText() {
  80. const {subscription} = this.props;
  81. // trial active
  82. if (subscription.isTrial) {
  83. return t('My Sentry Trial');
  84. }
  85. // cannot trial so must upgrade
  86. if (!subscription.canTrial) {
  87. return t('Upgrade Now');
  88. }
  89. // special performance trial
  90. if (!hasPerformance(subscription.planDetails)) {
  91. return t('Try Performance');
  92. }
  93. // normal business trial
  94. return t('Free Trial');
  95. }
  96. render() {
  97. const {subscription, organization, ...sidebarItemProps} = this.props;
  98. // XXX: The try business sidebar item also acts as an upsell of the
  99. // performance tier. So we'll actually want to show it to all users except
  100. // those on the current business plan (who are on the highest plan).
  101. if (
  102. (hasPerformance(subscription.planDetails) &&
  103. isBizPlanFamily(subscription.planDetails)) ||
  104. !subscription.canSelfServe
  105. ) {
  106. return null;
  107. }
  108. return (
  109. <TrialStartedSidebarItem {...{organization, subscription}}>
  110. {prefersStackedNav() ? (
  111. <TryBusinessNavigationItem
  112. subscription={subscription}
  113. label={this.labelText}
  114. onClick={this.openModal}
  115. />
  116. ) : (
  117. <SidebarItem
  118. {...sidebarItemProps}
  119. id="try-business"
  120. icon={<IconBusiness size="md" />}
  121. label={this.labelText}
  122. onClick={this.openModal}
  123. key="gs-try-business"
  124. data-test-id="try-business-sidebar"
  125. isNewSeenKeySuffix="-v1"
  126. isNew={!subscription.isTrial && subscription.canTrial}
  127. />
  128. )}
  129. </TrialStartedSidebarItem>
  130. );
  131. }
  132. }
  133. export default withSubscription(TryBusinessSidebarItem, {noLoader: true});