Sfoglia il codice sorgente

playerList ist now redux ready. need to implement filters and sorting and write actions like email or sms.

Tomi Cvetic 7 anni fa
parent
commit
5bee6748ac

+ 7 - 7
src/alerts/components/AlertList.js

@@ -14,20 +14,20 @@ class AlertView extends React.Component {
   }
 
   render () {
-    const { alert } = this.props
+    const { data } = this.props
     let alertIcon = ''
-    if (alert.type === 'info') {
+    if (data.severity === 'info') {
       alertIcon = 'glyphicon glyphicon-info-sign'
     }
-    if (alert.type === 'warning' || alert.type === 'danger') {
+    if (data.severity === 'warning' || data.severity === 'danger') {
       alertIcon = 'glyphicon glyphicon-remove-sign'
     }
-    if (alert.type === 'success') {
+    if (data.severity === 'success') {
       alertIcon = 'glyphicon glyphicon-ok-sign'
     }
     return (
-      <Alert bsStyle={alert.type} onDismiss={this.handleDismiss}>
-        <p><span className={alertIcon} /> {alert.text}</p>
+      <Alert bsStyle={data.severity} onDismiss={this.handleDismiss}>
+        <p><span className={alertIcon} /> {data.text}</p>
       </Alert>
     )
   }
@@ -41,7 +41,7 @@ class AlertList extends React.Component {
     if (alerts.length > 0) {
       return (
         <div className='alert-list'>
-          {alerts.map((alert, key) => <AlertView key={key} index={key} alert={alert} alertDismiss={alertDismiss} />)}
+          {alerts.map((data, key) => <AlertView key={key} index={key} data={data} alertDismiss={alertDismiss} />)}
         </div>
       )
     } else {

+ 6 - 5
src/alerts/index.js

@@ -7,12 +7,13 @@ const selectors = {}
 
 const middleware = store => next => action => {
   console.log('Alert middleware', store, next, action)
-  const { alert } = action
-  if (alert) {
-    // delete action.alert
+  const { alert, ...newAction } = action
+  if (!alert) {
+    return next(newAction)
   }
-  const result = next(action)
-  actions.alertAdd(alert)
+  const result = next(newAction)
+  console.log('would add new alert:', alert, newAction)
+  store.dispatch(actions.alertAdd(alert))
   return result
 }
 

+ 4 - 4
src/alerts/state.js

@@ -9,11 +9,11 @@
 
 /** actionTypes define what actions are handeled by the reducer. */
 export const actions = {
-  alertAdd: alert => {
-    console.log('adding alert', alert)
+  alertAdd: data => {
+    console.log('adding alert', data)
     return {
       type: 'ALERT_ADD',
-      alert
+      data
     }
   },
   alertDismiss: alertId => {
@@ -36,7 +36,7 @@ console.log('State state', state)
 export function reducer (state = [], action) {
   switch (action.type) {
     case 'ALERT_ADD':
-      return { ...state, alerts: [ ...state.alerts, action.alert ] }
+      return { ...state, alerts: [ ...state.alerts, action.data ] }
     case 'ALERT_DISMISS':
       return { ...state, alerts: [ ...state.alerts.slice(0, action.alertId), ...state.alerts.slice(action.alertId + 1) ] }
     default:

+ 14 - 12
src/excel/index.js

@@ -54,19 +54,21 @@ function saveAs (workbook, filename) {
   FileSaver.saveAs(new Blob([s2ab(wbout)], {type: ''}), filename)
 }
 
-function readWorkbook (file, callback) {
-  const reader = new FileReader()
-  reader.onload = (e) => {
-    const data = e.target.result
-    const workbook = XLSX.read(data, {type: 'binary', cellDates: true})
-    console.log('Workbook after read:', workbook)
-    if (workbook.SheetNames.length !== 1) {
-      throw Error(`Expected only one worksheet in the file, but found ${workbook.SheetNames.length}.`)
+function readWorkbook (file) {
+  return new Promise((resolve, reject) => {
+    const reader = new FileReader()
+    reader.onload = (e) => {
+      const data = e.target.result
+      const workbook = XLSX.read(data, {type: 'binary', cellDates: true})
+      console.log('Workbook after read:', workbook)
+      const worksheets = {}
+      Object.keys(workbook.Sheets).forEach(sheetName => {
+        worksheets[sheetName] = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], { header: 1, raw: true })
+      })
+      resolve(worksheets)
     }
-    const worksheet = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { header: 1, raw: true })
-    callback(worksheet)
-  }
-  reader.readAsBinaryString(file)
+    reader.readAsBinaryString(file)
+  })
 }
 
 export default { Workbook, SheetFromArray, saveAs, readWorkbook }

+ 43 - 8
src/index.js

@@ -58,18 +58,53 @@ function * rootSaga () {
 /** Create the saga middleware */
 const sagaMiddleware = createSagaMiddleware()
 
+const logger = store => next => action => {
+  console.log('dispatching', action)
+  let result = next(action)
+  console.log('next state', store.getState())
+  return result
+}
+
+const crashReporter = store => next => action => {
+  try {
+    return next(action)
+  } catch (err) {
+    console.error('Caught an exception!', err)
+    throw err
+  }
+}
+
+const middleware = [
+  logger,
+  crashReporter,
+  alerts.middleware,
+  sagaMiddleware
+]
 /** The enhancer allows to use Redux development tools in Chrome */
-const enhancers = compose(
-  applyMiddleware(alerts.middleware),
-  applyMiddleware(sagaMiddleware),
-  window.devToolsExtension ? window.devToolsExtension() : f => f
-)
-console.log('Enhancers:', enhancers)
+// see: https://github.com/zalmoxisus/redux-devtools-extension/issues/220
+let enhancer
+if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
+  enhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__(
+    applyMiddleware(...middleware)
+  )
+} else {
+  enhancer = compose(
+    applyMiddleware(...middleware)
+  )
+}
+// const enhancer = compose(
+//   applyMiddleware(alerts.middleware),
+//   applyMiddleware(sagaMiddleware),
+//   applyMiddleware(logger),
+//   applyMiddleware(crashReporter),
+//   window.devToolsExtension ? window.devToolsExtension() : f => f
+// )
+console.log('Enhancers:', enhancer)
 
 /** Build the Redux store from the rootReducer, the defualtState and the enhancers. */
-const store = createStore(rootReducer, defaultState, enhancers)
-sagaMiddleware.run(rootSaga)
+const store = createStore(rootReducer, defaultState, enhancer)
 console.log('Store:', store)
+sagaMiddleware.run(rootSaga)
 /** react-route is not used in this project.
 const history = syncHistoryWithStore(browserHistory, store)
 console.log('history:', history)

+ 14 - 0
src/playerList/components/PlayerActions.js

@@ -0,0 +1,14 @@
+import React from 'react'
+
+class PlayerActions extends React.Component {
+  render () {
+    return (
+      <ul>
+        <li><a>E-Mail</a></li>
+        <li><a>SMS</a></li>
+      </ul>
+    )
+  }
+}
+
+export default PlayerActions

+ 19 - 5
src/playerList/components/PlayerFilter.js

@@ -1,5 +1,5 @@
 import React from 'react'
-import { FormGroup, ControlLabel, FormControl, HelpBlock } from 'react-bootstrap'
+import { FormGroup, ControlLabel, FormControl, HelpBlock, Checkbox } from 'react-bootstrap'
 
 function FieldGroup ({ id, label, help, ...props }) {
   return (
@@ -16,11 +16,25 @@ class PlayerFilter extends React.Component {
     return (
       <form>
         <FieldGroup
-          id='playerListFile'
-          type='file'
-          label='playerList.xls File'
-          help='Die Datei wird von der Swisstennis Turniersoftware generiert.'
+          id='filterName'
+          type='text'
+          label='Name'
         />
+        <FormGroup>
+          <Checkbox inline>
+            Junior
+          </Checkbox>
+          <Checkbox inline>
+            Bezahlt
+          </Checkbox>
+        </FormGroup>
+        <FormGroup controlId='filterCategory'>
+          <ControlLabel>Konkurrenz</ControlLabel>
+          <FormControl componentClass='select' placeholder='Konkurrenz'>
+            <option value='WS 45+'>WS 45+</option>
+            <option value='MS 18&U'>MS 18&U</option>
+          </FormControl>
+        </FormGroup>
       </form>
     )
   }

+ 1 - 1
src/playerList/components/PlayerForm.js

@@ -47,7 +47,7 @@ class PlayerForm extends React.Component {
             help='Die Datei wird von der Swisstennis Turniersoftware generiert.'
             type='file'
             file={file}
-            inputRef={input => { this.playerListFile = input }} 
+            inputRef={input => { this.playerListFile = input }}
             onChange={this.handleFileUpload}
             disabled={(fileUpload === 'started')}
           />

+ 2 - 2
src/playerList/components/PlayerList.js

@@ -1,5 +1,5 @@
 import React from 'react'
-import PlayerForm from './PlayerForm'
+import PlayerActions from './PlayerActions'
 import PlayerTable from './PlayerTable'
 import PlayerFilter from './PlayerFilter'
 
@@ -9,7 +9,7 @@ class PlayerList extends React.Component {
     return (
       <div>
         <h1>Spielerliste</h1>
-        <PlayerForm state={state} actions={actions} />
+        <PlayerActions state={state} actions={actions} />
         <PlayerFilter state={state} actions={actions} />
         <PlayerTable state={state} actions={actions} />
       </div>

+ 3 - 2
src/playerList/components/index.js

@@ -2,6 +2,7 @@ import PlayerList from './PlayerList'
 import PlayerForm from './PlayerForm'
 import PlayerTable from './PlayerTable'
 import PlayerFilter from './PlayerFilter'
+import PlayerActions from './PlayerActions'
 
-export { PlayerList, PlayerForm, PlayerTable, PlayerFilter }
-export default { PlayerList, PlayerForm, PlayerTable, PlayerFilter }
+export { PlayerList, PlayerForm, PlayerTable, PlayerFilter, PlayerActions }
+export default { PlayerList, PlayerForm, PlayerTable, PlayerFilter, PlayerActions }

+ 16 - 21
src/playerList/functions.js

@@ -1,25 +1,20 @@
 import Excel from '../excel'         // Helper files to create Excel files
 import Player from '../classes/player'
 
-function handlePlayerList (event) {
-  const file = this.playerList.files[0]
-  Excel.readWorkbook(file, this.generatePlayerList)
-}
-
-export function generatePlayerList (worksheet) {
-  console.log('About to read the player list.')
-    /* const worksheets = { ...this.state.worksheets }
-    worksheets['PlayerList'] = worksheet
-    this.setState({ worksheets }) */
-
-  if (worksheet[4].length !== 32 & worksheet[3][0] !== 'Konkurrenz' & worksheet[3][31] !== 'bezahlt') {
-    throw Error('Wrong file structure.')
-  }
-  const players = worksheet.slice(4, worksheet.length).map((playerData) => new Player.Player(playerData))
-  const player = { ...this.state.player }
-  player.players = players
-  this.setState({ player })
-  this.calculatePayDate()
-  this.filterPlayers()
-  console.log('State after generating player list:', this.state)
+export function generatePlayerList (file) {
+  return new Promise((resolve, reject) => {
+    console.log('About to read the player list.')
+    Excel.readWorkbook(file).then(worksheets => {
+      console.log('got worksheets', worksheets)
+      const worksheet = worksheets.Players
+      if (worksheet[4].length !== 32 & worksheet[3][0] !== 'Konkurrenz' & worksheet[3][31] !== 'bezahlt') {
+        reject(Error('Wrong file structure.'))
+      }
+      const players = worksheet.slice(4, worksheet.length).map((playerData) => new Player.Player(playerData))
+      console.log('State after generating player list:', players)
+      resolve(players)
+    }).catch(error => {
+      reject(Error(error))
+    })
+  })
 }

+ 0 - 18
src/playerList/index.js

@@ -23,24 +23,6 @@ function calculatePlayerFilters () {
   this.setState({ player })
 }
 
-function generatePlayerList (worksheet) {
-  console.log('About to read the player list.')
-    /* const worksheets = { ...this.state.worksheets }
-    worksheets['PlayerList'] = worksheet
-    this.setState({ worksheets }) */
-
-  if (worksheet[4].length !== 32 & worksheet[3][0] !== 'Konkurrenz' & worksheet[3][31] !== 'bezahlt') {
-    throw Error('Wrong file structure.')
-  }
-  const players = worksheet.slice(4, worksheet.length).map((playerData) => new Player.Player(playerData))
-  const player = { ...this.state.player }
-  player.players = players
-  this.setState({ player })
-  this.calculatePayDate()
-  this.filterPlayers()
-  console.log('State after generating player list:', this.state)
-}
-
 function filterPlayers () {
   const filters = {
     junior: this.playerJunior.checked,

+ 13 - 3
src/playerList/state.js

@@ -33,6 +33,11 @@ export const actions = {
       type: 'PLAYER_FILE_UPLOAD_FAILURE',
       alert: { type: 'warning', text: error.toString() }
     }
+  },
+  filterPlayers: () => {
+    return {
+      type: 'PLAYER_FILTER'
+    }
   }
 }
 console.log('State actions', actions)
@@ -41,7 +46,7 @@ console.log('State actions', actions)
 export const state = {
   allPlayers: [],
   filteredPlayers: [],
-  filters: {},
+  filters: [],
   fileUpload: 'idle',
   file: null
 }
@@ -50,14 +55,18 @@ console.log('State state', state)
 /** reducer is called by the redux dispatcher and handles all component actions */
 export function reducer (state = [], action) {
   switch (action.type) {
-    case 'SET_PLAYERS':
-      return { ...state, allPlayers: action.players }
     case 'PLAYER_FILE_UPLOAD_START':
       return { ...state, fileUpload: 'started', file: action.file }
     case 'PLAYER_FILE_UPLOAD_SUCCESS':
       return { ...state, fileUpload: 'finished', allPlayers: action.allPlayers }
     case 'PLAYER_FILE_UPLOAD_FAILURE':
       return { ...state, fileUpload: 'failure' }
+    case 'PLAYER_FILTER':
+      const { allPlayers, filters } = state
+      const filteredPlayers = allPlayers.filter(player =>
+        filters.length ? filters.map(filter => filter(player)).every() : true
+      )
+      return { ...state, filteredPlayers }
     default:
       return state
   }
@@ -69,6 +78,7 @@ function * uploadFile (action) {
     const allPlayers = yield call(generatePlayerList, action.file)
     console.log('PlayerList success!', actions.fileUploadSuccess(allPlayers))
     yield put(actions.fileUploadSuccess(allPlayers))
+    yield put(actions.filterPlayers())
   } catch (error) {
     console.log('PlayerList failure!', actions.fileUploadFailure(error))
     yield put(actions.fileUploadFailure(error))