index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {Component} from 'react';
  2. import styled from '@emotion/styled';
  3. import {addErrorMessage} from 'sentry/actionCreators/indicator';
  4. import EmailField from 'sentry/components/forms/fields/emailField';
  5. import Form from 'sentry/components/forms/form';
  6. import NarrowLayout from 'sentry/components/narrowLayout';
  7. import {IconMegaphone} from 'sentry/icons';
  8. import {t, tct} from 'sentry/locale';
  9. import {space} from 'sentry/styles/space';
  10. import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
  11. import {trackAnalytics} from 'sentry/utils/analytics';
  12. type Props = RouteComponentProps<{orgId: string}, {}>;
  13. type State = {
  14. submitSuccess: boolean | null;
  15. };
  16. class OrganizationJoinRequest extends Component<Props, State> {
  17. state: State = {
  18. submitSuccess: null,
  19. };
  20. handleSubmitSuccess = () => {
  21. const {params, location} = this.props;
  22. this.setState({submitSuccess: true});
  23. trackAnalytics('join_request.created', {
  24. organization: params.orgId,
  25. referrer: location.query.referrer,
  26. });
  27. };
  28. handleSubmitError() {
  29. addErrorMessage(t('Request to join failed'));
  30. }
  31. handleCancel = e => {
  32. e.preventDefault();
  33. const {params} = this.props;
  34. window.location.assign(`/auth/login/${params.orgId}/`);
  35. };
  36. render() {
  37. const {params} = this.props;
  38. const {submitSuccess} = this.state;
  39. if (submitSuccess) {
  40. return (
  41. <NarrowLayout maxWidth="550px">
  42. <SuccessModal>
  43. <StyledIconMegaphone size="xxl" />
  44. <StyledHeader>{t('Request Sent')}</StyledHeader>
  45. <StyledText>{t('Your request to join has been sent.')}</StyledText>
  46. <ReceiveEmailMessage>
  47. {t('You will receive an email when your request is approved.')}
  48. </ReceiveEmailMessage>
  49. </SuccessModal>
  50. </NarrowLayout>
  51. );
  52. }
  53. return (
  54. <NarrowLayout maxWidth="650px">
  55. <StyledIconMegaphone size="xxl" />
  56. <StyledHeader data-test-id="join-request">{t('Request to Join')}</StyledHeader>
  57. <StyledText>
  58. {tct('Ask the admins if you can join the [orgId] organization.', {
  59. orgId: params.orgId,
  60. })}
  61. </StyledText>
  62. <Form
  63. requireChanges
  64. apiEndpoint={`/organizations/${params.orgId}/join-request/`}
  65. apiMethod="POST"
  66. submitLabel={t('Request to Join')}
  67. onSubmitSuccess={this.handleSubmitSuccess}
  68. onSubmitError={this.handleSubmitError}
  69. onCancel={this.handleCancel}
  70. >
  71. <StyledEmailField
  72. name="email"
  73. inline={false}
  74. label={t('Email Address')}
  75. placeholder="name@example.com"
  76. />
  77. </Form>
  78. </NarrowLayout>
  79. );
  80. }
  81. }
  82. const SuccessModal = styled('div')`
  83. display: grid;
  84. justify-items: center;
  85. text-align: center;
  86. padding-top: 10px;
  87. padding-bottom: ${space(4)};
  88. `;
  89. const StyledIconMegaphone = styled(IconMegaphone)`
  90. padding-bottom: ${space(3)};
  91. `;
  92. const StyledHeader = styled('h3')`
  93. margin-bottom: ${space(1)};
  94. `;
  95. const StyledText = styled('p')`
  96. margin-bottom: 0;
  97. `;
  98. const ReceiveEmailMessage = styled(StyledText)`
  99. max-width: 250px;
  100. `;
  101. const StyledEmailField = styled(EmailField)`
  102. padding-top: ${space(2)};
  103. padding-left: 0;
  104. `;
  105. export default OrganizationJoinRequest;