platformDocHeader.tsx 5.1 KB

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