invite.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { useCallback } from 'react'
  2. import PropTypes from 'prop-types'
  3. import { useShareProjectContext } from './share-project-modal'
  4. import Icon from '../../../shared/components/icon'
  5. import { Button, Col, Row, OverlayTrigger, Tooltip } from 'react-bootstrap'
  6. import { Trans, useTranslation } from 'react-i18next'
  7. import MemberPrivileges from './member-privileges'
  8. import { resendInvite, revokeInvite } from '../utils/api'
  9. import { useProjectContext } from '../../../shared/context/project-context'
  10. export default function Invite({ invite, isAdmin }) {
  11. return (
  12. <Row className="project-invite">
  13. <Col xs={7}>
  14. <div>{invite.email}</div>
  15. <div className="small">
  16. <Trans i18nKey="invite_not_accepted" />
  17. .&nbsp;
  18. {isAdmin && <ResendInvite invite={invite} />}
  19. </div>
  20. </Col>
  21. <Col xs={3} className="text-left">
  22. <MemberPrivileges privileges={invite.privileges} />
  23. </Col>
  24. {isAdmin && (
  25. <Col xs={2} className="text-center">
  26. <RevokeInvite invite={invite} />
  27. </Col>
  28. )}
  29. </Row>
  30. )
  31. }
  32. Invite.propTypes = {
  33. invite: PropTypes.object.isRequired,
  34. isAdmin: PropTypes.bool.isRequired,
  35. }
  36. function ResendInvite({ invite }) {
  37. const { monitorRequest } = useShareProjectContext()
  38. const project = useProjectContext()
  39. // const buttonRef = useRef(null)
  40. //
  41. const handleClick = useCallback(
  42. () =>
  43. monitorRequest(() => resendInvite(project, invite)).finally(() => {
  44. // NOTE: disabled as react-bootstrap v0.33.1 isn't forwarding the ref to the `button`
  45. // if (buttonRef.current) {
  46. // buttonRef.current.blur()
  47. // }
  48. document.activeElement.blur()
  49. }),
  50. [invite, monitorRequest, project]
  51. )
  52. return (
  53. <Button
  54. bsStyle="link"
  55. className="btn-inline-link"
  56. onClick={handleClick}
  57. // ref={buttonRef}
  58. >
  59. <Trans i18nKey="resend" />
  60. </Button>
  61. )
  62. }
  63. ResendInvite.propTypes = {
  64. invite: PropTypes.object.isRequired,
  65. }
  66. function RevokeInvite({ invite }) {
  67. const { t } = useTranslation()
  68. const { updateProject, monitorRequest } = useShareProjectContext()
  69. const project = useProjectContext()
  70. function handleClick(event) {
  71. event.preventDefault()
  72. monitorRequest(() => revokeInvite(project, invite)).then(() => {
  73. updateProject({
  74. invites: project.invites.filter(existing => existing !== invite),
  75. })
  76. })
  77. }
  78. return (
  79. <OverlayTrigger
  80. placement="bottom"
  81. overlay={
  82. <Tooltip id="tooltip-revoke-invite">
  83. <Trans i18nKey="revoke_invite" />
  84. </Tooltip>
  85. }
  86. >
  87. <Button
  88. type="button"
  89. bsStyle="link"
  90. onClick={handleClick}
  91. aria-label={t('revoke')}
  92. className="btn-inline-link"
  93. >
  94. <Icon type="times" />
  95. </Button>
  96. </OverlayTrigger>
  97. )
  98. }
  99. RevokeInvite.propTypes = {
  100. invite: PropTypes.object.isRequired,
  101. }