productSelectionAvailability.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import {useMemo} from 'react';
  2. import Link from 'sentry/components/links/link';
  3. import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types';
  4. import type {
  5. DisabledProducts,
  6. ProductSelectionProps,
  7. } from 'sentry/components/onboarding/productSelection';
  8. import {ProductSelection} from 'sentry/components/onboarding/productSelection';
  9. import {t, tct} from 'sentry/locale';
  10. import type {Organization} from 'sentry/types/organization';
  11. import withSubscription from 'getsentry/components/withSubscription';
  12. import {useAM2ProfilingUpsellModal} from 'getsentry/hooks/useAM2ProfilingUpsellModal';
  13. import {useAM2UpsellModal} from 'getsentry/hooks/useAM2UpsellModal';
  14. import type {Subscription} from 'getsentry/types';
  15. import {
  16. makeLinkToManageSubscription,
  17. makeLinkToOwnersAndBillingMembers,
  18. } from './profiling/alerts';
  19. function getDisabledProducts({
  20. organization,
  21. canSelfServe,
  22. showSessionReplayModal,
  23. showProfilingModal,
  24. }: {
  25. canSelfServe: boolean;
  26. organization: Organization;
  27. showProfilingModal: () => void;
  28. showSessionReplayModal: () => void;
  29. }): DisabledProducts {
  30. const disabledProducts: DisabledProducts = {};
  31. const hasSessionReplay = organization.features.includes('session-replay');
  32. const hasPerformance = organization.features.includes('performance-view');
  33. const hasProfiling = organization.features.includes('profiling-view');
  34. const hasBillingAccess = organization.access?.includes('org:billing');
  35. // if performance is not available, it means that users are on a MM* plan and we don't have an upsell modal to show.
  36. const shouldShowUpsellModals = hasPerformance && hasBillingAccess && canSelfServe;
  37. if (!hasPerformance) {
  38. const reason = hasBillingAccess
  39. ? t("To use Performance, update your organization's plan to its latest version.")
  40. : t(
  41. 'To use Performance, request an owner in your organization to update its plan to the latest version.'
  42. );
  43. disabledProducts[ProductSolution.PERFORMANCE_MONITORING] = {
  44. reason,
  45. };
  46. }
  47. if (!hasSessionReplay) {
  48. const reason = canSelfServe
  49. ? hasBillingAccess
  50. ? t(
  51. "To use Session Replay, update your organization's plan to its latest version."
  52. )
  53. : tct(
  54. 'To use Session Replay, request an owner in your organization to update its plan to the latest version. [link:See who can upgrade]',
  55. {
  56. link: (
  57. <Link
  58. to={makeLinkToOwnersAndBillingMembers(
  59. organization,
  60. 'profiling_onboarding_product-selector'
  61. )}
  62. />
  63. ),
  64. }
  65. )
  66. : tct(
  67. "To use Session Replay, update your organization's plan to its latest version. [link:Manage subscription]",
  68. {
  69. link: (
  70. <Link
  71. to={makeLinkToManageSubscription(
  72. organization,
  73. 'profiling_onboarding_product-selector'
  74. )}
  75. />
  76. ),
  77. }
  78. );
  79. disabledProducts[ProductSolution.SESSION_REPLAY] = {
  80. reason,
  81. onClick: shouldShowUpsellModals ? showSessionReplayModal : undefined,
  82. };
  83. }
  84. if (!hasProfiling) {
  85. const reason = canSelfServe
  86. ? hasBillingAccess
  87. ? t("To use Profiling, update your organization's plan to its latest version.")
  88. : tct(
  89. 'To use Profiling, request an owner in your organization to update its plan to the latest version. [link:See who can upgrade]',
  90. {
  91. link: (
  92. <Link
  93. to={makeLinkToOwnersAndBillingMembers(
  94. organization,
  95. 'profiling_onboarding_product-selector'
  96. )}
  97. />
  98. ),
  99. }
  100. )
  101. : tct(
  102. "To use Profiling, update your organization's plan to its latest version. [link:Manage subscription]",
  103. {
  104. link: (
  105. <Link
  106. to={makeLinkToManageSubscription(
  107. organization,
  108. 'profiling_onboarding_product-selector'
  109. )}
  110. />
  111. ),
  112. }
  113. );
  114. disabledProducts[ProductSolution.PROFILING] = {
  115. reason,
  116. onClick: shouldShowUpsellModals ? showProfilingModal : undefined,
  117. };
  118. }
  119. return disabledProducts;
  120. }
  121. type Props = {
  122. subscription: Subscription;
  123. } & Omit<ProductSelectionProps, 'disabledProducts'>;
  124. function ProductSelectionAvailabilityContainer({
  125. organization,
  126. subscription,
  127. platform,
  128. onChange,
  129. onLoad,
  130. }: Props) {
  131. // Disable requests for session replay upsell modal if the organization already has session replay
  132. const hasSessionReplay = organization.features.includes('session-replay');
  133. const sessionReplayUpsellModal = useAM2UpsellModal({
  134. subscription,
  135. surface: 'profiling',
  136. onComplete: () => {
  137. window.location.reload();
  138. },
  139. enabled: !hasSessionReplay,
  140. });
  141. const profilingUpsellModal = useAM2ProfilingUpsellModal({
  142. subscription,
  143. onComplete: () => {
  144. window.location.reload();
  145. },
  146. });
  147. const disabledProducts: DisabledProducts = useMemo(
  148. () =>
  149. getDisabledProducts({
  150. organization,
  151. canSelfServe: subscription.canSelfServe,
  152. showSessionReplayModal: sessionReplayUpsellModal.showModal,
  153. showProfilingModal: profilingUpsellModal.showModal,
  154. }),
  155. [organization, subscription, sessionReplayUpsellModal, profilingUpsellModal]
  156. );
  157. return (
  158. <ProductSelection
  159. organization={organization}
  160. disabledProducts={disabledProducts}
  161. platform={platform}
  162. onChange={onChange}
  163. onLoad={onLoad}
  164. />
  165. );
  166. }
  167. export const ProductSelectionAvailability = withSubscription(
  168. ProductSelectionAvailabilityContainer
  169. );