123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- 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 (
- <div className='container'>
- <form>
- <label htmlFor='PlayerList'>Swisstennis PlayerList.xls</label>
- <input type='file' id='PlayerList' ref={(input) => { this.playerList = input }} accept='.xls' placeholder='PlayerList File' onChange={this.handlePlayerList} />
- <label htmlFor='Calendar'>Swisstennis Calendar.xls</label>
- <input type='file' id='Calendar' ref={(input) => { this.calendar = input }} accept='.xls' placeholder='Calendar File' onChange={this.handleCalendar} />
- <label htmlFor='Date'>Datum</label>
- <select id='Date' ref={(input) => { this.matchDate = input }} onChange={this.filterMatches}>
- <option>{FILTER_OFF}</option>
- {Object.keys(dates).map((key) => (
- <option key={key} value={dates[key]}>{key}</option>
- ))}
- </select>
- <label htmlFor='Place'>Ort</label>
- <select id='Place' ref={(input) => { this.matchPlace = input }} onChange={this.filterMatches}>
- <option>{FILTER_OFF}</option>
- {places.map((place, key) => (
- <option key={key}>{place}</option>
- ))}
- </select>
- <label htmlFor='MatchCategory'>Match Konkurrenz</label>
- <select id='MatchCategory' ref={(input) => { this.matchCategory = input }} onChange={this.filterMatches}>
- <option>{FILTER_OFF}</option>
- {matchCategories.map((category, key) => (
- <option key={key}>{category}</option>
- ))}
- </select>
- <label htmlFor='Junior'>Junior</label>
- <input id='Junior' ref={(input) => { this.playerJunior = input }} type='checkbox' onChange={this.filterPlayers} />
- <label htmlFor='Paid'>Bezahlt</label>
- <input id='Paid' ref={(input) => { this.playerPaid = input }} type='checkbox' onChange={this.filterPlayers} />
- <label htmlFor='PlayerCategory'>Spieler Konkurrenz</label>
- <select id='PlayerCategory' ref={(input) => { this.playerCategory = input }} onChange={this.filterPlayers}>
- <option>{FILTER_OFF}</option>
- {playerCategories.map((category, key) => (
- <option key={key}>{category}</option>
- ))}
- </select>
- <button onClick={this.generateSchedule} disabled={!this.props.matchList.filteredMatches.length}>Spielliste generieren</button>
- <button onClick={this.generatePayTable} disabled={(!this.props.matchList.filteredMatches.length | !this.props.playerList.filteredPlayers.length)}>Zahlliste generieren</button>
- <button onClick={this.generatePhoneList} disabled={!this.props.playerList.allPlayers.length}>Telefonliste generieren</button>
- </form>
- <MatchList match={this.props.matchList} />
- <PhoneList filtered={this.props.matchList.filteredMatches} players={this.props.playerList.allPlayers} />
- <EmailList filtered={this.props.matchList.filteredMatches} players={this.props.playerList.allPlayers} />
- <PlayerList player={this.props.playerList} />
- </div>
- )
- }
- }
- export default Main
|