labs-experiments-widget.tsx 3.9 KB

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