noUnresolvedIssues.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import {Component, Fragment, lazy, Suspense} from 'react';
  2. import styled from '@emotion/styled';
  3. import congratsRobotsPlaceholder from 'sentry-images/spot/congrats-robots-placeholder.jpg';
  4. import {t} from 'sentry/locale';
  5. import space from 'sentry/styles/space';
  6. const Placeholder = () => (
  7. <PlaceholderImage
  8. alt={t('Congrats, you have no unresolved issues')}
  9. src={congratsRobotsPlaceholder}
  10. />
  11. );
  12. const Message = ({
  13. title,
  14. subtitle,
  15. }: {
  16. subtitle: React.ReactNode;
  17. title: React.ReactNode;
  18. }) => (
  19. <Fragment>
  20. <EmptyMessage>{title}</EmptyMessage>
  21. <p>{subtitle}</p>
  22. </Fragment>
  23. );
  24. const CongratsRobotsVideo = lazy(() => import('./congratsRobots'));
  25. type State = {hasError: boolean};
  26. /**
  27. * Error boundary for loading the robots video.
  28. * This can error because of the file size of the video
  29. *
  30. * Silently ignore the error, this isn't really important enough to
  31. * capture in Sentry
  32. */
  33. class ErrorBoundary extends Component<{children: React.ReactNode}, State> {
  34. static getDerivedStateFromError(): State {
  35. return {
  36. hasError: true,
  37. };
  38. }
  39. state: State = {
  40. hasError: false,
  41. };
  42. render() {
  43. if (this.state.hasError) {
  44. return <Placeholder />;
  45. }
  46. return this.props.children;
  47. }
  48. }
  49. const NoUnresolvedIssues = ({
  50. title,
  51. subtitle,
  52. }: {
  53. subtitle: React.ReactNode;
  54. title: React.ReactNode;
  55. }) => (
  56. <Wrapper>
  57. <ErrorBoundary>
  58. <Suspense fallback={<Placeholder />}>
  59. <CongratsRobotsVideo />
  60. </Suspense>
  61. </ErrorBoundary>
  62. <Message title={title} subtitle={subtitle} />
  63. </Wrapper>
  64. );
  65. const Wrapper = styled('div')`
  66. display: flex;
  67. padding: ${space(4)} ${space(4)};
  68. flex-direction: column;
  69. align-items: center;
  70. text-align: center;
  71. color: ${p => p.theme.subText};
  72. @media (max-width: ${p => p.theme.breakpoints.small}) {
  73. font-size: ${p => p.theme.fontSizeMedium};
  74. }
  75. `;
  76. const EmptyMessage = styled('div')`
  77. font-weight: 600;
  78. @media (min-width: ${p => p.theme.breakpoints.small}) {
  79. font-size: ${p => p.theme.fontSizeExtraLarge};
  80. }
  81. `;
  82. const PlaceholderImage = styled('img')`
  83. max-height: 320px; /* This should be same height as video in CongratsRobots */
  84. `;
  85. export default NoUnresolvedIssues;