disabledDashboardPage.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import {Fragment, useEffect} from 'react';
  2. import styled from '@emotion/styled';
  3. import List from 'sentry/components/list';
  4. import ListItem from 'sentry/components/list/listItem';
  5. import {IconBusiness} from 'sentry/icons';
  6. import {t, tct} from 'sentry/locale';
  7. import type {Organization} from 'sentry/types/organization';
  8. import type {Plan} from 'getsentry/types';
  9. import {displayPlanName} from 'getsentry/utils/billing';
  10. import trackGetsentryAnalytics from 'getsentry/utils/trackGetsentryAnalytics';
  11. import DashboardBackground from './illustrations/dashboardsBackground';
  12. import PageUpsellOverlay from './pageUpsellOverlay';
  13. import PlanFeature from './planFeature';
  14. type Props = React.PropsWithChildren<{
  15. features: string[];
  16. organization: Organization;
  17. }>;
  18. const TextWrapper = styled('div')`
  19. width: 500px;
  20. `;
  21. function DisabledDashboardPage({
  22. organization,
  23. children: _children,
  24. features,
  25. ...props
  26. }: Props) {
  27. const renderPlan = ({plan}: {plan: Plan | null}) => (
  28. <strong>{t('%s Plan', displayPlanName(plan))}</strong>
  29. );
  30. const requiredPlan = tct(
  31. `Upgrade to our [basicPlan] to view Dashboards and to our [advancedPlan]
  32. to build and customize your own.`,
  33. {
  34. basicPlan: (
  35. <PlanFeature organization={organization} features={['dashboards-basic']}>
  36. {renderPlan}
  37. </PlanFeature>
  38. ),
  39. advancedPlan: (
  40. <PlanFeature organization={organization} features={['dashboards-edit']}>
  41. {renderPlan}
  42. </PlanFeature>
  43. ),
  44. }
  45. );
  46. const description = (
  47. <Fragment>
  48. <p>
  49. {t(
  50. "Data you don't need isn't helpful. Customize your organization's dashboard with time series graphs, maps, tables, and more"
  51. )}
  52. </p>
  53. <FeatureList
  54. symbol={<IconBusiness size="sm" />}
  55. data-test-id="dashboard-feature-list"
  56. >
  57. <ListItem>{t('Build and share dashboards')}</ListItem>
  58. <ListItem>{t('Easily customize widgets')}</ListItem>
  59. <ListItem>{t('Manage dashboards')}</ListItem>
  60. <ListItem>{t('Open widgets in Discover')}</ListItem>
  61. </FeatureList>
  62. </Fragment>
  63. );
  64. // emit the event when the page is loaded
  65. useEffect(() => {
  66. trackGetsentryAnalytics('growth.disabled_dashboard.viewed', {
  67. organization,
  68. });
  69. }, [organization]);
  70. return (
  71. <PageUpsellOverlay
  72. name={t('Dashboards Just Got Personal')}
  73. source="dashboards"
  74. description={description}
  75. data-test-id="mock-dashboards-page"
  76. organization={organization}
  77. requiredPlan={requiredPlan}
  78. features={features}
  79. background={DashboardBackground}
  80. defaultUpsellSelection="custom-dashboards"
  81. customWrapper={TextWrapper}
  82. positioningStrategy={({mainRect, anchorRect, wrapperRect}) => {
  83. // Center within the anchor on the x axis, until the wrapper is larger
  84. // than the anchor, then align the wrapper to the right within anchor.
  85. let x =
  86. (anchorRect.width - wrapperRect.width) /
  87. (anchorRect.width > wrapperRect.width ? 2 : 1) +
  88. anchorRect.x -
  89. mainRect.x;
  90. // Avoid overflowing onto the left of the page
  91. x = Math.max(20, x);
  92. // Vertically center within the anchor
  93. const y =
  94. (anchorRect.height - wrapperRect.height + 40) / 2 + anchorRect.y - mainRect.y;
  95. return {x, y};
  96. }}
  97. {...props}
  98. />
  99. );
  100. }
  101. const FeatureList = styled(List)`
  102. display: grid;
  103. grid-template-columns: 1fr 1fr;
  104. `;
  105. export default DisabledDashboardPage;