integration-widget.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { useCallback, useState, ReactNode } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import AccessibleModal from '../../../../shared/components/accessible-modal'
  4. import { Button, Modal } from 'react-bootstrap'
  5. import getMeta from '../../../../utils/meta'
  6. type IntegrationLinkingWidgetProps = {
  7. logo: ReactNode
  8. title: string
  9. description: string
  10. helpPath: string
  11. hasFeature?: boolean
  12. statusIndicator?: ReactNode
  13. linked?: boolean
  14. linkPath: string
  15. unlinkPath: string
  16. unlinkConfirmationTitle: string
  17. unlinkConfirmationText: string
  18. disabled?: boolean
  19. }
  20. export function IntegrationLinkingWidget({
  21. logo,
  22. title,
  23. description,
  24. helpPath,
  25. hasFeature,
  26. statusIndicator,
  27. linked,
  28. linkPath,
  29. unlinkPath,
  30. unlinkConfirmationTitle,
  31. unlinkConfirmationText,
  32. disabled,
  33. }: IntegrationLinkingWidgetProps) {
  34. const { t } = useTranslation()
  35. const [showModal, setShowModal] = useState(false)
  36. const handleUnlinkClick = useCallback(() => {
  37. setShowModal(true)
  38. }, [])
  39. const handleModalHide = useCallback(() => {
  40. setShowModal(false)
  41. }, [])
  42. return (
  43. <div className="settings-widget-container">
  44. <div>{logo}</div>
  45. <div className="description-container">
  46. <div className="title-row">
  47. <h4>{title}</h4>
  48. {!hasFeature && (
  49. <span className="label label-info">{t('premium_feature')}</span>
  50. )}
  51. </div>
  52. <p className="small">
  53. {description}{' '}
  54. <a href={helpPath} target="_blank" rel="noreferrer">
  55. {t('learn_more')}
  56. </a>
  57. </p>
  58. {hasFeature && statusIndicator}
  59. </div>
  60. <div>
  61. <ActionButton
  62. hasFeature={hasFeature}
  63. upgradePath="/user/subscription/plans"
  64. linked={linked}
  65. handleUnlinkClick={handleUnlinkClick}
  66. linkPath={linkPath}
  67. disabled={disabled}
  68. />
  69. </div>
  70. <UnlinkConfirmationModal
  71. show={showModal}
  72. title={unlinkConfirmationTitle}
  73. content={unlinkConfirmationText}
  74. unlinkPath={unlinkPath}
  75. handleHide={handleModalHide}
  76. />
  77. </div>
  78. )
  79. }
  80. type ActionButtonProps = {
  81. hasFeature?: boolean
  82. upgradePath: string
  83. linked?: boolean
  84. handleUnlinkClick: () => void
  85. linkPath: string
  86. disabled?: boolean
  87. }
  88. function ActionButton({
  89. hasFeature,
  90. upgradePath,
  91. linked,
  92. handleUnlinkClick,
  93. linkPath,
  94. disabled,
  95. }: ActionButtonProps) {
  96. const { t } = useTranslation()
  97. if (!hasFeature) {
  98. return (
  99. <a href={upgradePath} className="btn btn-info text-capitalize">
  100. {t('upgrade')}
  101. </a>
  102. )
  103. } else if (linked) {
  104. return (
  105. <button
  106. className="btn btn-danger"
  107. onClick={handleUnlinkClick}
  108. disabled={disabled}
  109. >
  110. {t('unlink')}
  111. </button>
  112. )
  113. } else {
  114. return (
  115. <a
  116. href={linkPath}
  117. className="btn btn-info text-capitalize"
  118. disabled={disabled}
  119. >
  120. {t('link')}
  121. </a>
  122. )
  123. }
  124. }
  125. type UnlinkConfirmModalProps = {
  126. show: boolean
  127. title: string
  128. content: string
  129. unlinkPath: string
  130. handleHide: () => void
  131. }
  132. function UnlinkConfirmationModal({
  133. show,
  134. title,
  135. content,
  136. unlinkPath,
  137. handleHide,
  138. }: UnlinkConfirmModalProps) {
  139. const { t } = useTranslation()
  140. const handleCancel = event => {
  141. event.preventDefault()
  142. handleHide()
  143. }
  144. return (
  145. <AccessibleModal show={show} onHide={handleHide}>
  146. <Modal.Header closeButton>
  147. <Modal.Title>{title}</Modal.Title>
  148. </Modal.Header>
  149. <Modal.Body className="modal-body-share">
  150. <p>{content}</p>
  151. </Modal.Body>
  152. <Modal.Footer>
  153. <form action={unlinkPath} method="POST" className="form-inline">
  154. <input type="hidden" name="_csrf" value={getMeta('ol-csrfToken')} />
  155. <Button onClick={handleCancel}>{t('cancel')}</Button>
  156. <Button type="submit" bsStyle="danger">
  157. {t('unlink')}
  158. </Button>
  159. </form>
  160. </Modal.Footer>
  161. </AccessibleModal>
  162. )
  163. }