bemusic/bemuse

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

Summary

Maintainability
A
1 hr
Test Coverage
import './ResultScene.scss'

import * as Analytics from '../analytics'
import * as QueryFlags from '../query-flags'

import React, { MouseEvent } from 'react'
import SceneToolbar, { SceneToolbarSpacer } from 'bemuse/ui/SceneToolbar'

import { Chart } from 'bemuse-types'
import FirstTimeTip from './FirstTimeTip'
import Flex from 'bemuse/ui/Flex'
import { Icon } from 'bemuse/fa'
import { MappingMode } from 'bemuse/rules/mapping-mode'
import MusicChartInfo from './MusicChartInfo'
import MusicChartSelectorItem from './MusicChartSelectorItem'
import RankingContainer from './RankingContainer'
import ResultExpertInfo from './ResultExpertInfo'
import ResultGrade from './ResultGrade'
import ResultTable from './ResultTable'
import Scene from 'bemuse/ui/Scene'
import SceneHeading from 'bemuse/ui/SceneHeading'

export interface Result {
  1: number
  2: number
  3: number
  4: number
  missed: number
  totalCombo: number
  maxCombo: number
  accuracy: number
  grade: string
  score: number
  deltas: readonly number[]
  totalNotes: number
  tainted: boolean
  log: string
}

const getTweetLink = ({ chart, result }: { chart: Chart; result: Result }) => {
  const title = chart.info.title
  let subtitle = chart.info.subtitles[0] || ''
  const score = result.score
  const grade = result.grade
  if (subtitle === '') {
    const { genre } = chart.info
    const lastBraceStart = genre.lastIndexOf('[')
    if (genre.endsWith(']') && lastBraceStart !== -1) {
      subtitle = genre.substring(lastBraceStart + 1, genre.length - 1)
    }
  }
  subtitle = subtitle.trim()
  if (subtitle !== '' && !/^[[(]/.test(subtitle)) subtitle = `[${subtitle}]`
  if (subtitle !== '') subtitle = ` ${subtitle}`
  let url = 'https://bemuse.ninja/'
  const server = QueryFlags.getMusicServer()
  if (server) {
    url =
      (/^http:/.test(server) ? 'http' : 'https') +
      '://bemuse.ninja/?server=' +
      encodeURIComponent(server)
  }
  const text =
    `Played:「 ${title}${subtitle} 」on #Bemuse (Score:${score} [${grade}])` +
    '\n' +
    `→ ${url}`
  return (
    'https://twitter.com/intent/tweet?related=bemusegame&text=' +
    encodeURIComponent(text)
  )
}

export interface ResultSceneProps {
  result: Result
  playMode: MappingMode
  lr2Timegate: unknown[]
  chart: Chart
  onReplay: () => void
  onExit: (e: MouseEvent) => void
}

const ResultScene = ({
  result,
  playMode,
  chart,
  lr2Timegate,
  onReplay,
  onExit,
}: ResultSceneProps) => {
  const onTweet = (e: MouseEvent<HTMLAnchorElement>) => {
    e.preventDefault()
    e.stopPropagation()
    Analytics.send('ResultScene', 'tweet')
    window.open(
      getTweetLink({ chart, result }),
      'intent',
      'width=550,height=420'
    )
  }

  const handleExit = (e: MouseEvent<HTMLDivElement>) => {
    onExit(e)
    Analytics.send('ResultScene', 'exit')
  }

  return (
    <Scene className='ResultScene'>
      <SceneHeading>
        Play Result
        <div className='ResultSceneのmode'>
          {playMode === 'KB' ? 'Keyboard' : 'BMS'} Mode
        </div>
      </SceneHeading>
      <div className='ResultSceneのreport'>
        <ResultTable result={result} />
      </div>
      <ResultGrade grade={result.grade} />
      <div className='ResultSceneのinformation'>
        <div className='ResultSceneのinformationHeader'>
          <div className='ResultSceneのchart'>
            <FirstTimeTip tip='Play again' featureKey='replayGame'>
              <MusicChartSelectorItem
                chart={chart}
                onChartClick={onReplay}
                isReplayable
              />
            </FirstTimeTip>
          </div>
          <MusicChartInfo info={chart.info} />
        </div>
        <div className='ResultSceneのinformationBody'>
          <RankingContainer
            result={result.tainted ? undefined : result}
            chart={chart}
            playMode={playMode}
          />
        </div>
        <div className='ResultSceneのinformationFooter'>
          <a
            href={getTweetLink({ chart, result })}
            className='ResultSceneのtweet'
            onClick={onTweet}
          >
            <Icon name='twitter' />
          </a>
          <Flex grow={1} />
          <FirstTimeTip tip='Back to music selection' featureKey='finishGame'>
            <div className='ResultSceneのexit' onClick={handleExit}>
              Continue
            </div>
          </FirstTimeTip>
        </div>
      </div>
      <SceneToolbar>
        <span>
          <ResultExpertInfo deltas={result.deltas} />
        </span>
        <SceneToolbarSpacer />
        <a onClick={onExit}>Continue</a>
      </SceneToolbar>
    </Scene>
  )
}

export default ResultScene