edit-member.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import React, { useState, useEffect } from 'react'
  2. import PropTypes from 'prop-types'
  3. import { Trans, useTranslation } from 'react-i18next'
  4. import {
  5. useProjectContext,
  6. useShareProjectContext
  7. } from './share-project-modal'
  8. import Icon from '../../../shared/components/icon'
  9. import TransferOwnershipModal from './transfer-ownership-modal'
  10. import {
  11. Button,
  12. Col,
  13. Form,
  14. FormControl,
  15. FormGroup,
  16. OverlayTrigger,
  17. Tooltip
  18. } from 'react-bootstrap'
  19. import { removeMemberFromProject, updateMember } from '../utils/api'
  20. export default function EditMember({ member }) {
  21. const [privileges, setPrivileges] = useState(member.privileges)
  22. const [
  23. confirmingOwnershipTransfer,
  24. setConfirmingOwnershipTransfer
  25. ] = useState(false)
  26. // update the local state if the member's privileges change externally
  27. useEffect(() => {
  28. setPrivileges(member.privileges)
  29. }, [member.privileges])
  30. const { updateProject, monitorRequest } = useShareProjectContext()
  31. const project = useProjectContext()
  32. function handleSubmit(event) {
  33. event.preventDefault()
  34. if (privileges === 'owner') {
  35. setConfirmingOwnershipTransfer(true)
  36. } else {
  37. monitorRequest(() =>
  38. updateMember(project, member, {
  39. privilegeLevel: privileges
  40. })
  41. ).then(() => {
  42. updateProject({
  43. members: project.members.map(item =>
  44. item._id === member._id ? { ...item, privileges } : item
  45. )
  46. })
  47. })
  48. }
  49. }
  50. if (confirmingOwnershipTransfer) {
  51. return (
  52. <TransferOwnershipModal
  53. member={member}
  54. cancel={() => setConfirmingOwnershipTransfer(false)}
  55. />
  56. )
  57. }
  58. return (
  59. <Form horizontal id="share-project-form" onSubmit={handleSubmit}>
  60. <FormGroup className="project-member">
  61. <Col xs={7}>
  62. <FormControl.Static>{member.email}</FormControl.Static>
  63. </Col>
  64. <Col xs={3}>
  65. <SelectPrivilege
  66. value={privileges}
  67. handleChange={event => setPrivileges(event.target.value)}
  68. />
  69. </Col>
  70. <Col xs={2}>
  71. {privileges === member.privileges ? (
  72. <RemoveMemberAction member={member} />
  73. ) : (
  74. <ChangePrivilegesActions
  75. handleReset={() => setPrivileges(member.privileges)}
  76. />
  77. )}
  78. </Col>
  79. </FormGroup>
  80. </Form>
  81. )
  82. }
  83. EditMember.propTypes = {
  84. member: PropTypes.shape({
  85. _id: PropTypes.string.isRequired,
  86. email: PropTypes.string.isRequired,
  87. privileges: PropTypes.string.isRequired
  88. })
  89. }
  90. function SelectPrivilege({ value, handleChange }) {
  91. const { t } = useTranslation()
  92. return (
  93. <FormControl
  94. componentClass="select"
  95. className="privileges"
  96. bsSize="sm"
  97. value={value}
  98. onChange={handleChange}
  99. >
  100. <option value="owner">{t('owner')}</option>
  101. <option value="readAndWrite">{t('can_edit')}</option>
  102. <option value="readOnly">{t('read_only')}</option>
  103. </FormControl>
  104. )
  105. }
  106. SelectPrivilege.propTypes = {
  107. value: PropTypes.string.isRequired,
  108. handleChange: PropTypes.func.isRequired
  109. }
  110. function RemoveMemberAction({ member }) {
  111. const { updateProject, monitorRequest } = useShareProjectContext()
  112. const project = useProjectContext()
  113. function handleClick(event) {
  114. event.preventDefault()
  115. monitorRequest(() => removeMemberFromProject(project, member)).then(() => {
  116. updateProject({
  117. members: project.members.filter(existing => existing !== member)
  118. })
  119. })
  120. }
  121. return (
  122. <FormControl.Static className="text-center">
  123. <OverlayTrigger
  124. placement="bottom"
  125. overlay={
  126. <Tooltip id="tooltip-remove-collaborator">
  127. <Trans i18nKey="remove_collaborator" />
  128. </Tooltip>
  129. }
  130. >
  131. <Button
  132. type="button"
  133. bsStyle="link"
  134. onClick={handleClick}
  135. className="remove-button"
  136. aria-label="Remove from project"
  137. >
  138. <Icon type="times" />
  139. </Button>
  140. </OverlayTrigger>
  141. </FormControl.Static>
  142. )
  143. }
  144. RemoveMemberAction.propTypes = {
  145. member: PropTypes.shape({
  146. _id: PropTypes.string.isRequired,
  147. email: PropTypes.string.isRequired,
  148. privileges: PropTypes.string.isRequired
  149. })
  150. }
  151. function ChangePrivilegesActions({ handleReset }) {
  152. return (
  153. <div className="text-center">
  154. <Button type="submit" bsSize="sm" bsStyle="success">
  155. <Trans i18nKey="change_or_cancel-change" />
  156. </Button>
  157. <div className="text-sm">
  158. <Trans i18nKey="change_or_cancel-or" />
  159. &nbsp;
  160. <Button type="button" className="btn-inline-link" onClick={handleReset}>
  161. <Trans i18nKey="change_or_cancel-cancel" />
  162. </Button>
  163. </div>
  164. </div>
  165. )
  166. }
  167. ChangePrivilegesActions.propTypes = {
  168. handleReset: PropTypes.func.isRequired
  169. }