labs-experiments-widget.tsx 3.9 KB

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