use-tutorial.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { useCallback, useState } from 'react'
  2. import * as eventTracking from '@/infrastructure/event-tracking'
  3. import { postJSON } from '@/infrastructure/fetch-json'
  4. import { debugConsole } from '@/utils/debugging'
  5. import { useEditorContext } from '@/shared/context/editor-context'
  6. const useTutorial = (
  7. tutorialKey: string,
  8. eventData: Record<string, any> = {}
  9. ) => {
  10. const [showPopup, setShowPopup] = useState(false)
  11. const { deactivateTutorial, currentPopup, setCurrentPopup } =
  12. useEditorContext()
  13. const completeTutorial = useCallback(
  14. async ({
  15. event = 'promo-click',
  16. action = 'complete',
  17. ...rest
  18. }: {
  19. event: string
  20. action: 'complete' | 'postpone'
  21. } & Record<string, any>) => {
  22. eventTracking.sendMB(event, { ...eventData, ...rest })
  23. try {
  24. await postJSON(`/tutorial/${tutorialKey}/${action}`)
  25. } catch (err) {
  26. debugConsole.error(err)
  27. }
  28. setShowPopup(false)
  29. deactivateTutorial(tutorialKey)
  30. },
  31. [deactivateTutorial, eventData, tutorialKey]
  32. )
  33. const dismissTutorial = useCallback(
  34. async (eventName: string = 'promo-dismiss') => {
  35. await completeTutorial({
  36. event: eventName,
  37. action: 'complete',
  38. })
  39. },
  40. [completeTutorial]
  41. )
  42. const maybeLater = useCallback(async () => {
  43. await completeTutorial({
  44. event: 'promo-click',
  45. action: 'postpone',
  46. button: 'maybe-later',
  47. })
  48. }, [completeTutorial])
  49. // try to show the popup if we don't already have one showing, returns true if it can show, false if it can't
  50. const tryShowingPopup = useCallback(
  51. (eventName: string = 'promo-prompt') => {
  52. if (currentPopup === null) {
  53. setCurrentPopup(tutorialKey)
  54. setShowPopup(true)
  55. eventTracking.sendMB(eventName, eventData)
  56. return true
  57. }
  58. return false
  59. },
  60. [currentPopup, setCurrentPopup, tutorialKey, eventData]
  61. )
  62. const clearPopup = useCallback(() => {
  63. // popups should only clear themselves, in cases they need to cleanup or shouldnt show anymore
  64. // allow forcing the clear if needed, eg: higher prio alert needs to show
  65. if (currentPopup === tutorialKey) {
  66. setCurrentPopup(null)
  67. setShowPopup(false)
  68. }
  69. }, [setCurrentPopup, setShowPopup, currentPopup, tutorialKey])
  70. const clearAndShow = useCallback(
  71. (eventName: string = 'promo-prompt') => {
  72. setCurrentPopup(tutorialKey)
  73. setShowPopup(true)
  74. eventTracking.sendMB(eventName, eventData)
  75. },
  76. [setCurrentPopup, setShowPopup, tutorialKey, eventData]
  77. )
  78. const hideUntilReload = useCallback(() => {
  79. clearPopup()
  80. deactivateTutorial(tutorialKey)
  81. }, [clearPopup, deactivateTutorial, tutorialKey])
  82. return {
  83. completeTutorial,
  84. dismissTutorial,
  85. maybeLater,
  86. tryShowingPopup,
  87. clearPopup,
  88. clearAndShow,
  89. showPopup,
  90. hideUntilReload,
  91. }
  92. }
  93. export default useTutorial