appStoreConnectContext.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {createContext, useEffect, useMemo, useState} from 'react';
  2. import {Organization, Project} from 'sentry/types';
  3. import {
  4. AppStoreConnectCredentialsStatus,
  5. AppStoreConnectStatusData,
  6. } from 'sentry/types/debugFiles';
  7. import {getAppStoreValidationErrorMessage} from 'sentry/utils/appStoreValidationErrorMessage';
  8. import useApi from 'sentry/utils/useApi';
  9. export type AppStoreConnectContextProps =
  10. | Record<string, AppStoreConnectStatusData>
  11. | undefined;
  12. const AppStoreConnectContext = createContext<AppStoreConnectContextProps>(undefined);
  13. type ProviderProps = {
  14. children: React.ReactNode;
  15. organization: Organization;
  16. project?: Project;
  17. };
  18. const Provider = ({children, project, organization}: ProviderProps) => {
  19. const api = useApi();
  20. const [projectDetails, setProjectDetails] = useState<undefined | Project>();
  21. const [appStoreConnectStatusData, setAppStoreConnectStatusData] =
  22. useState<AppStoreConnectContextProps>(undefined);
  23. const appStoreConnectSymbolSources = useMemo(() => {
  24. return (
  25. projectDetails?.symbolSources ? JSON.parse(projectDetails.symbolSources) : []
  26. ).reduce((acc, {type, id, ...symbolSource}) => {
  27. if (type.toLowerCase() === 'appstoreconnect') {
  28. acc[id] = {type, ...symbolSource};
  29. }
  30. return acc;
  31. }, {});
  32. }, [projectDetails?.symbolSources]);
  33. useEffect(() => {
  34. if (!project || projectDetails) {
  35. return undefined;
  36. }
  37. if (project.symbolSources) {
  38. setProjectDetails(project);
  39. return undefined;
  40. }
  41. let unmounted = false;
  42. api
  43. .requestPromise(`/projects/${organization.slug}/${project.slug}/`)
  44. .then(responseProjectDetails => {
  45. if (unmounted) {
  46. return;
  47. }
  48. setProjectDetails(responseProjectDetails);
  49. })
  50. .catch(() => {
  51. // We do not care about the error
  52. });
  53. return () => {
  54. unmounted = true;
  55. };
  56. }, [project, organization, api]);
  57. useEffect(() => {
  58. if (!projectDetails) {
  59. return undefined;
  60. }
  61. if (!Object.keys(appStoreConnectSymbolSources).length) {
  62. return undefined;
  63. }
  64. let unmounted = false;
  65. api
  66. .requestPromise(
  67. `/projects/${organization.slug}/${projectDetails.slug}/appstoreconnect/status/`
  68. )
  69. .then(appStoreConnectStatus => {
  70. if (unmounted) {
  71. return;
  72. }
  73. setAppStoreConnectStatusData(appStoreConnectStatus);
  74. })
  75. .catch(() => {
  76. // We do not care about the error
  77. });
  78. return () => {
  79. unmounted = true;
  80. };
  81. }, [projectDetails, organization, appStoreConnectSymbolSources]);
  82. function getUpdateAlertMessage(
  83. respository: NonNullable<Parameters<typeof getAppStoreValidationErrorMessage>[1]>,
  84. credentials: AppStoreConnectCredentialsStatus
  85. ) {
  86. if (credentials?.status === 'valid') {
  87. return undefined;
  88. }
  89. return getAppStoreValidationErrorMessage(credentials, respository);
  90. }
  91. return (
  92. <AppStoreConnectContext.Provider
  93. value={
  94. appStoreConnectStatusData && project
  95. ? Object.keys(appStoreConnectStatusData).reduce((acc, key) => {
  96. const appStoreConnect = appStoreConnectStatusData[key];
  97. return {
  98. ...acc,
  99. [key]: {
  100. ...appStoreConnect,
  101. updateAlertMessage: getUpdateAlertMessage(
  102. {
  103. name: appStoreConnectSymbolSources[key].name,
  104. link: `/settings/${organization.slug}/projects/${project.slug}/debug-symbols/?customRepository=${key}`,
  105. },
  106. appStoreConnect.credentials
  107. ),
  108. },
  109. };
  110. }, {})
  111. : undefined
  112. }
  113. >
  114. {children}
  115. </AppStoreConnectContext.Provider>
  116. );
  117. };
  118. export {Provider};
  119. export default AppStoreConnectContext;