useOnboardingDocs.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import {useEffect, useState} from 'react';
  2. import * as Sentry from '@sentry/react';
  3. import {loadDocs} from 'sentry/actionCreators/projects';
  4. import platforms from 'sentry/data/platforms';
  5. import {Project} from 'sentry/types';
  6. import useApi from 'sentry/utils/useApi';
  7. import useOrganization from 'sentry/utils/useOrganization';
  8. const INITIAL_LOADING_DOCS = {};
  9. const INITIAL_DOC_CONTENTS = {};
  10. type Options = {
  11. docKeys: string[];
  12. isPlatformSupported: boolean;
  13. project: Project;
  14. };
  15. function useOnboardingDocs({docKeys, isPlatformSupported, project}: Options) {
  16. const organization = useOrganization();
  17. const api = useApi();
  18. const [loadingDocs, setLoadingDocs] =
  19. useState<Record<string, boolean>>(INITIAL_LOADING_DOCS);
  20. const [docContents, setDocContents] =
  21. useState<Record<string, string>>(INITIAL_DOC_CONTENTS);
  22. const currentPlatform = project.platform
  23. ? platforms.find(p => p.id === project.platform)
  24. : undefined;
  25. useEffect(() => {
  26. if (!isPlatformSupported) {
  27. if (loadingDocs !== INITIAL_LOADING_DOCS) {
  28. setLoadingDocs(INITIAL_LOADING_DOCS);
  29. }
  30. if (docContents !== INITIAL_DOC_CONTENTS) {
  31. setDocContents(INITIAL_DOC_CONTENTS);
  32. }
  33. return;
  34. }
  35. docKeys.forEach(docKey => {
  36. if (docKey in loadingDocs) {
  37. // If a documentation content is loading, we should not attempt to fetch it again.
  38. // otherwise, if it's not loading, we should only fetch at most once.
  39. // Any errors that occurred will be captured via Sentry.
  40. return;
  41. }
  42. const setLoadingDoc = (loadingState: boolean) =>
  43. setLoadingDocs(prevState => {
  44. return {
  45. ...prevState,
  46. [docKey]: loadingState,
  47. };
  48. });
  49. const setDocContent = (docContent: string | undefined) =>
  50. setDocContents(prevState => {
  51. if (docContent === undefined) {
  52. const newState = {
  53. ...prevState,
  54. };
  55. delete newState[docKey];
  56. return newState;
  57. }
  58. return {
  59. ...prevState,
  60. [docKey]: docContent,
  61. };
  62. });
  63. setLoadingDoc(true);
  64. loadDocs({
  65. api,
  66. orgSlug: organization.slug,
  67. projectSlug: project.slug,
  68. platform: docKey as any,
  69. })
  70. .then(({html}) => {
  71. setDocContent(html as string);
  72. setLoadingDoc(false);
  73. })
  74. .catch(error => {
  75. Sentry.captureException(error);
  76. setDocContent(undefined);
  77. setLoadingDoc(false);
  78. });
  79. });
  80. }, [
  81. currentPlatform,
  82. docKeys,
  83. isPlatformSupported,
  84. api,
  85. loadingDocs,
  86. organization.slug,
  87. project.slug,
  88. docContents,
  89. ]);
  90. if (!currentPlatform || !isPlatformSupported) {
  91. return {
  92. isLoading: false,
  93. hasOnboardingContents: false,
  94. docContents: {},
  95. };
  96. }
  97. const isLoading = Boolean(
  98. docKeys?.some(key => {
  99. if (key in loadingDocs) {
  100. return !!loadingDocs[key];
  101. }
  102. return true;
  103. })
  104. );
  105. const hasOnboardingContents = Boolean(
  106. docKeys?.every(key => typeof docContents[key] === 'string')
  107. );
  108. return {
  109. docKeys,
  110. isLoading,
  111. hasOnboardingContents,
  112. docContents,
  113. };
  114. }
  115. export default useOnboardingDocs;