bemusic/bemuse

View on GitHub
bemuse/src/app/ui/TitleScene.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import './TitleScene.scss'

import * as Analytics from '../analytics'

import React, { MouseEvent, useContext, useState } from 'react'
import { lastSeenVersion, optionsSlice } from '../entities/Options'
import { useDispatch, useSelector } from 'react-redux'

import AboutScene from './AboutScene'
import ChangelogPanel from './ChangelogPanel'
import HomePage from 'bemuse/site/HomePage'
import ModalPopup from 'bemuse/ui/ModalPopup'
import ModeSelectScene from './ModeSelectScene'
import Scene from 'bemuse/ui/Scene'
import { SceneManagerContext } from 'bemuse/scene-manager'
import Toolbar from './Toolbar'
import { selectOptions } from '../redux/ReduxState'
import version from 'bemuse/utils/version'

const HAS_PARENT = (() => {
  try {
    return window.parent !== window
  } catch (e) {
    return false
  }
})()

const Version = () => (
  <>
    <strong>Bemuse</strong> v{version}
  </>
)

const toolbarItems = ({
  showAbout,
  viewChangelog,
  hasSeenChangelog,
}: {
  showAbout: (e: MouseEvent<HTMLAnchorElement>) => void
  viewChangelog: (e: MouseEvent<HTMLAnchorElement>) => void
  hasSeenChangelog: boolean
}) => [
  Toolbar.item('About', {
    onClick: showAbout,
  }),
  Toolbar.item('Community FAQ', {
    href: 'https://faq.bemuse.ninja',
    tip: 'New',
    tipFeatureKey: 'faq',
  }),
  Toolbar.item('Docs', {
    href: '/project/',
  }),
  Toolbar.item(<Version />, {
    onClick: viewChangelog,
    tip: 'What’s new?',
    tipVisible: !hasSeenChangelog,
  }),
  Toolbar.spacer(),
  Toolbar.item('Discord', {
    href: 'https://discord.gg/aB6ucmx',
    tip: 'Join our community',
    tipFeatureKey: 'discord',
  }),
  Toolbar.item('Twitter', {
    href: 'https://twitter.com/bemusegame',
  }),
  Toolbar.item('GitHub', {
    href: 'https://github.com/bemusic/bemuse',
  }),
]

const TitleScene = () => {
  const sceneManager = useContext(SceneManagerContext)
  const dispatch = useDispatch()
  const options = useSelector(selectOptions)

  const onMarkChangelogAsSeen = () => {
    dispatch(
      optionsSlice.actions.UPDATE_LAST_SEEN_VERSION({ newVersion: version })
    )
  }

  const hasSeenChangelog = lastSeenVersion(options) === version

  const [changelogModalVisible, setChangelogModalVisible] = useState(false)

  const enterGame = () => {
    sceneManager.push(<ModeSelectScene />)
    Analytics.send('TitleScene', 'enter game')
  }

  const showAbout = () => {
    sceneManager.push(<AboutScene />)
    Analytics.send('TitleScene', 'show about')
  }

  const viewChangelog = () => {
    toggleChangelogModal()
    onMarkChangelogAsSeen()
    Analytics.send('TitleScene', 'view changelog')
  }

  const toggleChangelogModal = () => {
    setChangelogModalVisible((flag) => !flag)
  }

  const shouldShowHomepage = !HAS_PARENT
  return (
    <Scene className='TitleScene'>
      <div className='TitleSceneのimage' />
      <div className='TitleSceneのpage'>
        <div className='TitleSceneのpageTitle'>
          <div className='TitleSceneのlogo'>
            <div className='TitleSceneのtagline'>
              online, web-based rhythm game
            </div>
            <img src={require('./images/logo-with-shadow.svg')} />
          </div>
          <div className='TitleSceneのenter'>
            <a onClick={enterGame} data-testid='enter-game'>
              Enter Game
            </a>
          </div>
        </div>
        {shouldShowHomepage ? (
          <div className='TitleSceneのpageContents'>
            <HomePage />
          </div>
        ) : null}
      </div>
      <Toolbar
        items={toolbarItems({ hasSeenChangelog, showAbout, viewChangelog })}
      />
      <div className='TitleSceneのcurtain' />
      <ModalPopup
        visible={changelogModalVisible}
        onBackdropClick={() => toggleChangelogModal()}
      >
        <ChangelogPanel />
      </ModalPopup>
    </Scene>
  )
}

export default TitleScene