packages feed

kurita-0: client/src/KuritaState.ts

import clone from 'lodash/clone'
import {createContext, useCallback, useEffect, useReducer} from 'react'

import KuritaClient, {ServerEvent, ServerBracketState} from './KuritaClient'

type KuritaState = {
  bracket?: ServerBracketState,
}

type KuritaAction = (
  {
    type: 'receive-event',
    payload: ServerEvent,
  } | {
    type: 'send-vote',
    payload: string,
  }
)

const initialState: KuritaState = {
  bracket: undefined,
}

function reducer(state: KuritaState, action: KuritaAction): KuritaState {
  switch (action.type) {
    case 'receive-event':
      switch (action.payload.event) {
        case 'start':
          return {
            ...state,
            bracket: action.payload.bracket,
          }

        case 'score':
          const newState = clone(state)
          if (newState.bracket) {
            newState.bracket.current.game = action.payload.scores
          }
          return newState
      }

    case 'send-vote':
      const newState = clone(state)
      const votedCompetitor = newState.bracket.current.game.find(
        ({competitor}) => competitor === action.payload
      )
      votedCompetitor.score++
      return newState
      
    default:
      return state
  }
}

export function useKurita(client: KuritaClient): [KuritaState, (action: KuritaAction) => void] {
  const [state, dispatch] = useReducer(reducer, initialState)

  const fullDispatch = useCallback(
    (action: KuritaAction) => {
      if (action.type === 'send-vote') {
        client.send({
          event: 'vote',
          for: action.payload,
        })
      }
      dispatch(action)
    },
    [client],
  )

  useEffect(() => {
    const unsubscribe = client.subscribe(event => {
      dispatch({type: 'receive-event', payload: event})
    })
    return unsubscribe
  }, [client])

  return [state, fullDispatch]
}