use-tutorial.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. export 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: 'promo-click' | 'promo-dismiss'
  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(async () => {
  34. await completeTutorial({
  35. event: 'promo-dismiss',
  36. action: 'complete',
  37. })
  38. }, [completeTutorial])
  39. const maybeLater = useCallback(async () => {
  40. await completeTutorial({
  41. event: 'promo-click',
  42. action: 'postpone',
  43. button: 'maybe-later',
  44. })
  45. }, [completeTutorial])
  46. // try to show the popup if we don't already have one showing, returns true if it can show, false if it can't
  47. const tryShowingPopup = useCallback(() => {
  48. if (currentPopup === null) {
  49. setCurrentPopup(tutorialKey)
  50. setShowPopup(true)
  51. eventTracking.sendMB('promo-prompt', eventData)
  52. return true
  53. }
  54. return false
  55. }, [currentPopup, setCurrentPopup, tutorialKey, eventData])
  56. const clearPopup = useCallback(
  57. (force: boolean = false) => {
  58. // popups should only clear themselves, in cases they need to cleanup or shouldnt show anymore
  59. // allow forcing the clear if needed, eg: higher prio alert needs to show
  60. if (force || currentPopup === tutorialKey) {
  61. setCurrentPopup(null)
  62. setShowPopup(false)
  63. }
  64. },
  65. [setCurrentPopup, setShowPopup, currentPopup, tutorialKey]
  66. )
  67. return {
  68. completeTutorial,
  69. dismissTutorial,
  70. maybeLater,
  71. tryShowingPopup,
  72. clearPopup,
  73. showPopup,
  74. }
  75. }
  76. export default useTutorial