labs-experiments-widget.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { ReactNode, useCallback } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import OLBadge from '@/shared/components/ol/ol-badge'
  4. import OLTooltip from '@/shared/components/ol/ol-tooltip'
  5. import { postJSON } from '@/infrastructure/fetch-json'
  6. import OLButton from '@/shared/components/ol/ol-button'
  7. import getMeta from '@/utils/meta'
  8. type IntegrationLinkingWidgetProps = {
  9. logo: ReactNode
  10. title: string
  11. description: string | ReactNode
  12. optedInDescription?: string | ReactNode
  13. helpPath?: string
  14. labsEnabled?: boolean
  15. experimentName: string
  16. setErrorMessage: (message: string) => void
  17. optedIn: boolean
  18. setOptedIn: (optedIn: boolean) => void
  19. }
  20. export function LabsExperimentWidget({
  21. logo,
  22. title,
  23. description,
  24. optedInDescription,
  25. helpPath,
  26. labsEnabled,
  27. experimentName,
  28. setErrorMessage,
  29. optedIn,
  30. setOptedIn,
  31. }: IntegrationLinkingWidgetProps) {
  32. const { t } = useTranslation()
  33. const experimentsErrorMessage = t(
  34. 'we_are_unable_to_opt_you_into_this_experiment'
  35. )
  36. const allowedExperiments = getMeta('ol-allowedExperiments')
  37. const disabled = !allowedExperiments.includes(experimentName) && !optedIn
  38. const handleEnable = useCallback(async () => {
  39. try {
  40. const enablePath = `/labs/participate/experiments/${experimentName}/opt-in`
  41. await postJSON(enablePath)
  42. setOptedIn(true)
  43. } catch (err) {
  44. setErrorMessage(experimentsErrorMessage)
  45. }
  46. }, [experimentName, setErrorMessage, experimentsErrorMessage, setOptedIn])
  47. const handleDisable = useCallback(async () => {
  48. try {
  49. const disablePath = `/labs/participate/experiments/${experimentName}/opt-out`
  50. await postJSON(disablePath)
  51. setOptedIn(false)
  52. } catch (err) {
  53. setErrorMessage(experimentsErrorMessage)
  54. }
  55. }, [experimentName, setErrorMessage, experimentsErrorMessage, setOptedIn])
  56. return (
  57. <div
  58. className={`labs-experiment-widget-container ${disabled ? 'disabled-experiment' : ''}`}
  59. >
  60. <div className="experiment-logo-container">{logo}</div>
  61. <div className="description-container">
  62. <div className="title-row">
  63. <h3 className="h4">{title}</h3>
  64. {optedIn && <OLBadge bg="info">{t('enabled')}</OLBadge>}
  65. </div>
  66. <p className="small">
  67. {optedIn && optedInDescription ? optedInDescription : description}{' '}
  68. {helpPath && (
  69. <a href={helpPath} target="_blank" rel="noreferrer">
  70. {t('learn_more')}
  71. </a>
  72. )}
  73. </p>
  74. </div>
  75. {disabled && (
  76. <div className="disabled-explanation">{t('experiment_full')}</div>
  77. )}
  78. <div>
  79. {labsEnabled && (
  80. <ActionButton
  81. optedIn={optedIn}
  82. handleDisable={handleDisable}
  83. handleEnable={handleEnable}
  84. disabled={disabled}
  85. />
  86. )}
  87. </div>
  88. </div>
  89. )
  90. }
  91. type ActionButtonProps = {
  92. optedIn?: boolean
  93. disabled?: boolean
  94. handleEnable: () => void
  95. handleDisable: () => void
  96. }
  97. function ActionButton({
  98. optedIn,
  99. disabled,
  100. handleEnable,
  101. handleDisable,
  102. }: ActionButtonProps) {
  103. const { t } = useTranslation()
  104. if (optedIn) {
  105. return (
  106. <OLButton variant="secondary" onClick={handleDisable}>
  107. {t('turn_off')}
  108. </OLButton>
  109. )
  110. } else if (disabled) {
  111. const tooltipableButton = (
  112. <div className="d-inline-block">
  113. <OLButton variant="primary" disabled>
  114. {t('turn_on')}
  115. </OLButton>
  116. </div>
  117. )
  118. return (
  119. <OLTooltip
  120. id="experiment-disabled"
  121. description={t('this_experiment_isnt_accepting_new_participants')}
  122. overlayProps={{ delay: 0 }}
  123. >
  124. {tooltipableButton}
  125. </OLTooltip>
  126. )
  127. } else {
  128. return (
  129. <OLButton variant="primary" onClick={handleEnable}>
  130. {t('turn_on')}
  131. </OLButton>
  132. )
  133. }
  134. }
  135. export default LabsExperimentWidget