import React from 'react' // React to manage the GUI import Player from './classes/player' import Match from './classes/match' import PlayerList from './playerList' // Everything that has to do with players import MatchList from './matchList' // Everything that has to do with matches import Excel from './excel' // Helper files to create Excel files import { date2s, time2s } from './helpers' import 'bootstrap/dist/css/bootstrap.css' import EmailList from './lists/components/EmailList' import PhoneList from './lists/components/PhoneList' /** * General Application Design * * 4 Components: * - PlayerList (representing the PlayerList Excel file) * - Calendar (representing the Calendar Excel file) * - MatchList (representing the Spielliste Excel file) * - PaymentList (representing the Zahlliste Excel file) * * PlayerList * - Shows the relevant information from the file * - Shows calculated information from combination with Calendar * - Points out potential problems * - Allows access to player information * * Calendar * - Shows the relevant information from the file * - Shows calculated information from combination with PlayerList * - Points out potential problems * - Allows access to match information * * MatchList * - Shows the calculated match lists * - Points out problems * * PaymentList * - Shows the calculated payment lists * - Points out problems * */ const FILTER_OFF = 'Alle' /** Main application */ class Main extends React.Component { /** * Constructor * Defines the state and binds all 'this' in all functions to the object. */ constructor () { super() // Bind 'this' to functions this.handlePlayerList = this.handlePlayerList.bind(this) this.handleCalendar = this.handleCalendar.bind(this) this.generatePlayerList = this.generatePlayerList.bind(this) this.generateCalendar = this.generateCalendar.bind(this) this.filterMatches = this.filterMatches.bind(this) this.filterPlayers = this.filterPlayers.bind(this) this.generateSchedule = this.generateSchedule.bind(this) this.generatePayTable = this.generatePayTable.bind(this) this.generatePhoneList = this.generatePhoneList.bind(this) } calculateMatchFilters () { const dates = {} const places = [] const categories = [] this.state.match.matches.forEach((item) => { const dateString = date2s(item.Datum) if (!!item.Datum & !dates.hasOwnProperty(dateString)) { dates[dateString] = item.Datum } if (!!item.Ort & !places.includes(item.Ort)) { places.push(item.Ort) } if (!!item.Konkurrenz & !categories.includes(item.Konkurrenz)) { categories.push(item.Konkurrenz) } }) const match = { ...this.state.match, dates, places, categories } this.setState({ match }) } calculatePlayerFilters () { const categories = [] this.state.player.players.forEach((item) => { if (!!item.Konkurrenz & !categories.includes(item.Konkurrenz)) { categories.push(item.Ort) } }) const player = { ...this.state.player, categories } this.setState({ player }) } handlePlayerList (event) { const file = this.playerList.files[0] Excel.readWorkbook(file, this.generatePlayerList) } handleCalendar (event) { const file = this.calendar.files[0] Excel.readWorkbook(file, this.generateCalendar) } 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) } generateCalendar (worksheet) { console.log('About to read the calendar.') const worksheets = { ...this.state.worksheets } worksheets['Calendar'] = worksheet this.setState({ worksheets }) if (worksheet[2].length < 8 | worksheet[2].length > 9) { throw Error('Wrong file structure.') } const matches = worksheet.slice(2, worksheet.length).map((matchData) => new Match.MatchClass(matchData)) const match = { ...this.state.match } match.matches = matches this.setState({ match }) this.calculateMatchFilters() this.calculatePayDate() this.filterMatches() console.log('State after generating calendar:', this.state) } filterMatches () { const filters = { date: this.matchDate.value !== FILTER_OFF ? this.matchDate.value : null, place: this.matchPlace.value !== FILTER_OFF ? this.matchPlace.value : null, category: this.matchCategory.value !== FILTER_OFF ? this.matchCategory.value : null } console.log('New filter settings:', filters) const match = { ...this.state.match } match.filtered = match.matches.filter((match) => { const matchDate = new Date(match.Datum) matchDate.setHours(0, 0, 0, 0) const filtDate = new Date(filters.date) filtDate.setHours(0, 0, 0, 0) return (!filters.date | matchDate.getTime() === filtDate.getTime()) & (!filters.place | filters.place === match.Ort) & (!filters.category | filters.category === match.Konkurrenz) }) this.setState({ match }) const player = { ...this.state.player, filters } player.filtered = player.players this.setState({ player }) } filterPlayers () { const filters = { junior: this.playerJunior.checked, paid: this.playerPaid.checked, category: this.playerCategory.value !== FILTER_OFF ? this.playerCategory.value : null } console.log('New filter settings:', filters) const player = { ...this.state.player, filters } player.filtered = player.players this.setState({ player }) } generateSchedule (event) { event.preventDefault() const matchlist = new Excel.Workbook() matchlist.SheetNames = [] matchlist.Sheets = {} const worksheets = {} let placeArray = this.state.match.places if (placeArray.length > 1) { placeArray = placeArray.concat([FILTER_OFF]) } const date = Object.keys(this.state.match.dates).find((key) => String(this.state.match.dates[key]) === this.matchDate.value ) placeArray.forEach(place => { let header = [ ['Stadtzürcher Tennismeisterschaft'], [`Spielplan für den ${date} (${place})`], [], ['Ort', 'Zeit', 'Kategorie', 'Spieler 1', '', 'Spieler 2', '', '1. Satz', '2. Satz', '3. Satz', 'WO Grund'] ] let matchListPerPlace = this.state.match.filtered.filter((match) => (match.Ort === place | place === FILTER_OFF)).map((match) => [match.Ort, time2s(match.Datum), match.Konkurrenz, match.Spieler1, match.Spieler1Klassierung, match.Spieler2, match.Spieler2Klassierung] ) console.log('Generated match list per place:', matchListPerPlace) worksheets[place] = Excel.SheetFromArray(header.concat(matchListPerPlace)) matchlist.SheetNames.push(place) matchlist.Sheets[place] = worksheets[place] }) Excel.saveAs(matchlist, 'Spielliste.xlsx') } generatePhoneList (event) { event.preventDefault() const phoneMail = new Excel.Workbook() phoneMail.SheetNames = [] phoneMail.Sheets = {} const dataList = [ ['Vorname', 'Nachname', 'Anrede', 'Geschlecht', 'Handy', 'E-Mail'] ] const phonePot = [] const players = this.state.player.filtered players.forEach(player => { if (!player.phone.match(/^FEHLER/) && !phonePot.includes(player.phone)) { phonePot.push(player.phone) dataList.push([ player.Vorname, player.Name, 2, player.geschlecht === 'w' ? 2 : 1, player.phone ]) } }) phoneMail.Sheets['Sheet1'] = Excel.SheetFromArray(dataList) phoneMail.SheetNames.push('Sheet1') Excel.saveAs(phoneMail, 'Telefon.xlsx') } calculatePayDate () { if ((this.state.player.players.length === 0) | (this.state.match.matches.length === 0)) { return } this.state.match.matches.forEach((match) => { [match.Spieler1, match.Spieler2].forEach((matchPlayer) => { if (matchPlayer) { let foundPlayer = this.state.player.players.find((player) => (player.name === matchPlayer) & (player.Konkurrenz === match.Konkurrenz) ) if (!foundPlayer) { console.log('Debug payerlist:', foundPlayer, match) throw Error('Match player not found in player list. This is an error!') } if (!foundPlayer.BezahltAm) { foundPlayer.BezahltAm = match.Datum } } }) }) } generatePayTable (event) { event.preventDefault() const paylist = new Excel.Workbook() paylist.SheetNames = [] paylist.Sheets = {} const worksheets = {} let placeArray = this.state.match.places /* if (placeArray.length > 1) { placeArray = placeArray.concat([FILTER_OFF]) } */ const date = Object.keys(this.state.match.dates).find((key) => String(this.state.match.dates[key]) === this.matchDate.value ) placeArray.forEach((place) => { let header = [ ['Stadtzürcher Tennismeisterschaft'], [`Nenngelder für ${date}`], [], [`${place}`, null, '50.- oder 30.- (Junioren Jg. 1999 oder jünger)'], [], ['bereits bez.', 'Kat.', 'Zeit', 'Name', 'Betrag bez.', 'Quittung abgeben'] ] // Per place let payListPerPlace = [] this.state.match.filtered.forEach((match) => { [match.Spieler1, match.Spieler2].forEach((matchPlayer) => { if (!!matchPlayer & (match.Ort === place | FILTER_OFF === place)) { const player = this.state.player.players.find((player) => (player.Konkurrenz === match.Konkurrenz) & (player.name === matchPlayer) ) let paid = null if (player.BezahltAm < this.matchDate.value) { paid = date2s(player.BezahltAm) } if (player.Bezahlt) { paid = 'OK' } let price if (player.isDoubles) { price = (player.isJunior ? 15 : 25) + (player.isJuniorDP ? 15 : 25) } else { price = player.isJunior ? 30 : 50 } payListPerPlace.push([ paid, match.Konkurrenz, time2s(match.Datum), `${matchPlayer} (${price}.-)` ]) } }) }) let footer = [ [], ['Datum'], ['Turnierleiter', null, null, 'Kassierer'], ['Betrag von Spielern erhalten', null, null, 'Betrag von Turnierleiter erhalten'] ] console.log(`Generated pay list per place ${place}:`, payListPerPlace) worksheets[place] = Excel.SheetFromArray(header.concat(payListPerPlace, footer)) paylist.SheetNames.push(place) paylist.Sheets[place] = worksheets[place] }) let payListPerPlace = [] this.state.match.filtered.forEach((match) => { [match.Spieler1, match.Spieler2].forEach((matchPlayer) => { if (matchPlayer) { const player = this.state.player.players.find((player) => (player.Konkurrenz === match.Konkurrenz) & (player.name === matchPlayer) ) let price if (player.isDoubles) { price = (player.isJunior ? 15 : 25) + (player.isJuniorDP ? 15 : 25) } else { price = player.isJunior ? 30 : 50 } payListPerPlace.push([ match.Ort, match.Konkurrenz, `${matchPlayer} (${price}.-)` ]) } }) }) console.log(`Generated pay list for "Alle":`, payListPerPlace) worksheets[FILTER_OFF] = Excel.SheetFromArray(payListPerPlace) paylist.SheetNames.push(FILTER_OFF) paylist.Sheets[FILTER_OFF] = worksheets[FILTER_OFF] Excel.saveAs(paylist, 'Zahlliste.xlsx') } render () { const places = this.props.matchList.places || [] const dates = this.props.matchList.dates || {} const matchCategories = this.props.matchList.categories || [] const playerCategories = this.props.playerList.categories || [] return (
{ this.playerList = input }} accept='.xls' placeholder='PlayerList File' onChange={this.handlePlayerList} /> { this.calendar = input }} accept='.xls' placeholder='Calendar File' onChange={this.handleCalendar} /> { this.playerJunior = input }} type='checkbox' onChange={this.filterPlayers} /> { this.playerPaid = input }} type='checkbox' onChange={this.filterPlayers} />
) } } export default Main