platformDocHeader.tsx 5.2 KB

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