platformDocHeader.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {useCallback} from 'react';
  2. import styled from '@emotion/styled';
  3. import {removeProject} from 'sentry/actionCreators/projects';
  4. import {Button} from 'sentry/components/button';
  5. import ButtonBar from 'sentry/components/buttonBar';
  6. import Confirm from 'sentry/components/confirm';
  7. import {useRecentCreatedProject} from 'sentry/components/onboarding/useRecentCreatedProject';
  8. import {Platform} from 'sentry/data/platformCategories';
  9. import {IconChevron} from 'sentry/icons/iconChevron';
  10. import {t} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import {Project} from 'sentry/types';
  13. import {trackAnalytics} from 'sentry/utils/analytics';
  14. import {handleXhrErrorResponse} from 'sentry/utils/handleXhrErrorResponse';
  15. import useApi from 'sentry/utils/useApi';
  16. import useOrganization from 'sentry/utils/useOrganization';
  17. import useRouter from 'sentry/utils/useRouter';
  18. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  19. type Props = {
  20. platform: Platform;
  21. projectSlug: Project['slug'];
  22. };
  23. export function PlatformDocHeader({platform, projectSlug}: Props) {
  24. const organization = useOrganization();
  25. const api = useApi();
  26. const router = useRouter();
  27. const projectDeletionOnBackClick = !!organization?.features.includes(
  28. 'onboarding-project-deletion-on-back-click'
  29. );
  30. const recentCreatedProject = useRecentCreatedProject({
  31. orgSlug: organization.slug,
  32. projectSlug,
  33. });
  34. const shallProjectBeDeleted =
  35. projectDeletionOnBackClick &&
  36. recentCreatedProject &&
  37. // if the project has received a first error, we don't delete it
  38. recentCreatedProject.firstError === false &&
  39. // if the project has received a first transaction, we don't delete it
  40. recentCreatedProject.firstTransaction === false &&
  41. // if the project has replays, we don't delete it
  42. recentCreatedProject.hasReplays === false &&
  43. // if the project has sessions, we don't delete it
  44. recentCreatedProject.hasSessions === false &&
  45. // if the project is older than one hour, we don't delete it
  46. recentCreatedProject.olderThanOneHour === false;
  47. const handleGoBack = useCallback(async () => {
  48. if (!recentCreatedProject) {
  49. return;
  50. }
  51. trackAnalytics('project_creation.back_button_clicked', {
  52. organization,
  53. });
  54. if (shallProjectBeDeleted) {
  55. trackAnalytics('project_creation.data_removal_modal_confirm_button_clicked', {
  56. organization,
  57. platform: recentCreatedProject.slug,
  58. project_id: recentCreatedProject.id,
  59. });
  60. try {
  61. await removeProject({
  62. api,
  63. orgSlug: organization.slug,
  64. projectSlug: recentCreatedProject.slug,
  65. origin: 'getting_started',
  66. });
  67. trackAnalytics('project_creation.data_removed', {
  68. organization,
  69. date_created: recentCreatedProject.dateCreated,
  70. platform: recentCreatedProject.slug,
  71. project_id: recentCreatedProject.id,
  72. });
  73. } catch (error) {
  74. handleXhrErrorResponse('Unable to delete project in project creation', error);
  75. // we don't give the user any feedback regarding this error as this shall be silent
  76. }
  77. }
  78. router.replace(
  79. normalizeUrl(
  80. `/organizations/${organization.slug}/projects/new/?referrer=getting-started&project=${recentCreatedProject.id}`
  81. )
  82. );
  83. }, [api, recentCreatedProject, organization, shallProjectBeDeleted, router]);
  84. return (
  85. <StyledPageHeader>
  86. <h2>{t('Configure %(platform)s SDK', {platform: platform.name ?? 'other'})}</h2>
  87. <ButtonBar gap={1}>
  88. <Confirm
  89. bypass={!shallProjectBeDeleted}
  90. message={t(
  91. "Hey, just a heads up - we haven't received any data for this SDK yet and by going back all changes will be discarded. Are you sure you want to head back?"
  92. )}
  93. priority="danger"
  94. confirmText={t("Yes I'm sure")}
  95. onConfirm={handleGoBack}
  96. onClose={() => {
  97. if (!recentCreatedProject) {
  98. return;
  99. }
  100. trackAnalytics('project_creation.data_removal_modal_dismissed', {
  101. organization,
  102. platform: recentCreatedProject.slug,
  103. project_id: recentCreatedProject.id,
  104. });
  105. }}
  106. onRender={() => {
  107. if (!recentCreatedProject) {
  108. return;
  109. }
  110. trackAnalytics('project_creation.data_removal_modal_rendered', {
  111. organization,
  112. platform: recentCreatedProject.slug,
  113. project_id: recentCreatedProject.id,
  114. });
  115. }}
  116. >
  117. <Button icon={<IconChevron direction="left" size="sm" />} size="sm">
  118. {t('Back to Platform Selection')}
  119. </Button>
  120. </Confirm>
  121. {platform.key !== 'other' && (
  122. <Button size="sm" href={platform.link ?? undefined} external>
  123. {t('Full Documentation')}
  124. </Button>
  125. )}
  126. </ButtonBar>
  127. </StyledPageHeader>
  128. );
  129. }
  130. const StyledPageHeader = styled('div')`
  131. display: flex;
  132. justify-content: space-between;
  133. margin-bottom: ${space(3)};
  134. h2 {
  135. margin: 0;
  136. }
  137. @media (max-width: ${p => p.theme.breakpoints.small}) {
  138. flex-direction: column;
  139. align-items: flex-start;
  140. h2 {
  141. margin-bottom: ${space(2)};
  142. }
  143. }
  144. `;