clone-project-modal-content.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* eslint-disable jsx-a11y/no-autofocus */
  2. import { FormEvent, useCallback, useMemo, useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import { postJSON } from '../../../infrastructure/fetch-json'
  5. import { CloneProjectTag } from './clone-project-tag'
  6. import {
  7. OLModalBody,
  8. OLModalFooter,
  9. OLModalHeader,
  10. OLModalTitle,
  11. } from '@/features/ui/components/ol/ol-modal'
  12. import Notification from '@/shared/components/notification'
  13. import OLForm from '@/features/ui/components/ol/ol-form'
  14. import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
  15. import OLFormControl from '@/features/ui/components/ol/ol-form-control'
  16. import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
  17. import OLButton from '@/features/ui/components/ol/ol-button'
  18. import { Tag } from '../../../../../app/src/Features/Tags/types'
  19. export default function CloneProjectModalContent({
  20. handleHide,
  21. inFlight,
  22. setInFlight,
  23. handleAfterCloned,
  24. projectId,
  25. projectName,
  26. projectTags,
  27. }: {
  28. handleHide: () => void
  29. inFlight: boolean
  30. setInFlight: (inFlight: boolean) => void
  31. handleAfterCloned: (clonedProject: any, tags: Tag[]) => void
  32. projectId: string
  33. projectName: string
  34. projectTags: Tag[]
  35. }) {
  36. const { t } = useTranslation()
  37. const [error, setError] = useState<string | boolean>()
  38. const [clonedProjectName, setClonedProjectName] = useState(
  39. `${projectName} (Copy)`
  40. )
  41. const [clonedProjectTags, setClonedProjectTags] = useState(projectTags)
  42. // valid if the cloned project has a name
  43. const valid = useMemo(
  44. () => clonedProjectName.trim().length > 0,
  45. [clonedProjectName]
  46. )
  47. // form submission: clone the project if the name is valid
  48. const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
  49. event.preventDefault()
  50. if (!valid) {
  51. return
  52. }
  53. setError(false)
  54. setInFlight(true)
  55. // clone the project
  56. postJSON(`/project/${projectId}/clone`, {
  57. body: {
  58. projectName: clonedProjectName,
  59. tags: clonedProjectTags.map(tag => ({ id: tag._id })),
  60. },
  61. })
  62. .then(data => {
  63. // open the cloned project
  64. handleAfterCloned(data, clonedProjectTags)
  65. })
  66. .catch(({ response, data }) => {
  67. if (response?.status === 400) {
  68. setError(data.message)
  69. } else {
  70. setError(true)
  71. }
  72. })
  73. .finally(() => {
  74. setInFlight(false)
  75. })
  76. }
  77. const removeTag = useCallback((tag: Tag) => {
  78. setClonedProjectTags(value => value.filter(item => item._id !== tag._id))
  79. }, [])
  80. return (
  81. <>
  82. <OLModalHeader closeButton>
  83. <OLModalTitle>{t('copy_project')}</OLModalTitle>
  84. </OLModalHeader>
  85. <OLModalBody>
  86. <OLForm id="clone-project-form" onSubmit={handleSubmit}>
  87. <OLFormGroup controlId="clone-project-form-name">
  88. <OLFormLabel>{t('new_name')}</OLFormLabel>
  89. <OLFormControl
  90. type="text"
  91. placeholder={t('new_project_name')}
  92. required
  93. value={clonedProjectName}
  94. onChange={event => setClonedProjectName(event.target.value)}
  95. autoFocus
  96. />
  97. </OLFormGroup>
  98. {clonedProjectTags.length > 0 && (
  99. <OLFormGroup
  100. controlId="clone-project-tags-list"
  101. className="clone-project-tag"
  102. >
  103. <OLFormLabel>{t('tags')}: </OLFormLabel>
  104. <div role="listbox" id="clone-project-tags-list">
  105. {clonedProjectTags.map(tag => (
  106. <CloneProjectTag
  107. key={tag._id}
  108. tag={tag}
  109. removeTag={removeTag}
  110. />
  111. ))}
  112. </div>
  113. </OLFormGroup>
  114. )}
  115. </OLForm>
  116. {error && (
  117. <Notification
  118. content={
  119. typeof error === 'string' && error.length
  120. ? error
  121. : t('generic_something_went_wrong')
  122. }
  123. type="error"
  124. />
  125. )}
  126. </OLModalBody>
  127. <OLModalFooter>
  128. <OLButton variant="secondary" disabled={inFlight} onClick={handleHide}>
  129. {t('cancel')}
  130. </OLButton>
  131. <OLButton
  132. variant="primary"
  133. disabled={inFlight || !valid}
  134. form="clone-project-form"
  135. type="submit"
  136. >
  137. {inFlight ? <>{t('copying')}…</> : t('copy')}
  138. </OLButton>
  139. </OLModalFooter>
  140. </>
  141. )
  142. }