Add ability to edit team name & starting lineup & save to server

This commit is contained in:
Garrett Mills 2020-11-05 20:57:08 -06:00
parent 47f3c0e6b0
commit fc5b90a938
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
7 changed files with 180 additions and 12 deletions

View File

@ -9,6 +9,19 @@ class Teams extends Controller {
return [...super.services, 'models']
}
/**
* Save changes to the current user's team and return it as API data.
* @param req
* @param res
* @param next
* @return {Promise<*>}
*/
async save_my_team(req, res, next) {
req.user_team.team_name = String(req.body.team_name).trim()
await req.user_team.save()
return res.api(await req.user_team.to_api())
}
/**
* Return the API data for the current user's team.
* Requires an authenticated user.
@ -41,11 +54,78 @@ class Teams extends Controller {
* @return {Promise<*>}
*/
async get_my_team_current_lineup(req, res, next) {
const Lineup = this.models.get('Lineup')
const lineup = await Lineup.get_and_update_for_team(req.user_team)
const lineup = await req.user_team.lineup()
return res.api(await lineup.to_api())
}
/**
* Saves the lineup for the current user's team and returns it as API data.
* @param req
* @param res
* @param next
* @return {Promise<void>}
*/
async save_my_team_lineup(req, res, next) {
if ( !Array.isArray(req.body.starting_players) ) {
return res.status(400)
.message('Missing required field: starting_players')
.api()
}
if ( !Array.isArray(req.body.benched_players) ) {
return res.status(400)
.message('Missing required field: benched_players')
.api()
}
const player_ids = (await req.user_team.players()).map(x => x.id)
const lineup = await req.user_team.lineup()
lineup.clear_lineup()
for ( const player of req.body.starting_players ) {
if ( !player.id || !player.position ) continue;
const lineup_record = {
player_id: player.id,
position: player.position,
}
if ( !player_ids.includes(lineup_record.player_id) ) {
return res.status(400)
.message(`Sorry, the player ${lineup_record.player_id} is not on your team.`)
.api()
}
lineup.start_player(lineup_record)
}
for ( const player of req.body.benched_players ) {
if ( !player.id ) continue;
if ( !player_ids.includes(player.id) ) {
return res.status(400)
.message(`Sorry, the player ${player.id} is not on your team.`)
.api()
}
lineup.bench_player(player)
}
console.log('pre save', lineup)
// Save the partial lineup
await lineup.save()
console.log('post save', lineup)
// Fetch a fresh version to fill in any missing players
const corrected_lineup = await req.user_team.lineup()
console.log('corrected', corrected_lineup)
return res.api(await corrected_lineup.to_api())
}
/**
* Return the API data for a list of all teams.
* @param req

View File

@ -138,6 +138,24 @@ class Lineup extends Model {
}
}
/**
* Given the player_id/position record, add it to the starting lineup.
* @param {object} player_position_record
*/
start_player(player_position_record) {
this.benched_player_ids = this.benched_player_ids.filter(x => x !== player_position_record.player_id)
this.starting_players = this.starting_players.filter(x => x.player_id !== player_position_record.player_id)
this.starting_players.push(player_position_record)
}
/**
* Remove all players from the bench and the starting lineup.
*/
clear_lineup() {
this.starting_players = []
this.benched_player_ids = []
}
/**
* Cast the lineup to an object which can be returned via the API.
* @return {Promise<object>}
@ -159,12 +177,20 @@ class Lineup extends Model {
// Find the player instance and cast it to an API object
const player_inst = starting_players.find(x => x.id === player.player_id)
build_starting_players.push({
position: player.position,
...(await player_inst.to_api())
...(await player_inst.to_api()),
position: player.position
})
// remove the position from the array of positions to back-fill
lineup_positions = lineup_positions.filter(x => x !== player.position)
let found_one = false
lineup_positions = lineup_positions.filter(x => {
if ( !found_one && x === player.position ) {
found_one = true
return false
}
return true
})
}
// Fill in any missing positions into the data
@ -182,6 +208,11 @@ class Lineup extends Model {
build_benched_players.push(obj)
}
// If there are no players on the bench, add a placeholder slot.
if ( build_benched_players.length < 1 ) {
build_benched_players.push({ position: 'B' })
}
data.starting_players = build_starting_players
data.benched_players = build_benched_players
return data

View File

@ -67,6 +67,7 @@ class Player extends Model {
async to_api() {
return {
id: this.id,
number: this.player_number,
name: this.full_name,
position: this.fantasy_position,

View File

@ -50,6 +50,11 @@ class Team extends Model {
return new_team
}
async lineup() {
const Lineup = this.models.get('Lineup')
return Lineup.get_and_update_for_team(this)
}
async players() {
const Player = this.models.get('Player')
return Player.find({

View File

@ -60,7 +60,8 @@ const index = {
* or middleware that are applied in order.
*/
post: {
'/my-team': ['controller::Teams.save_my_team'],
'/my-team/lineup': ['controller::Teams.save_my_team_lineup'],
},
// You can include other HTTP verbs here.

View File

@ -47,6 +47,11 @@ class MyTeamComponent extends Component {
static get template() { return template }
static get props() { return [] }
/**
* Original team name to compare against.
*/
_original_team_name = ''
/**
* The team name.
* @type {string}
@ -105,7 +110,7 @@ class MyTeamComponent extends Component {
return `
<div class="center">
<img src="${data.image}" alt="${data.name}" height="50" style="border-radius: 50%">
<span>${data.name} (${data.number})</span>
<span>${data.name} (#${data.number})</span>
</div>
`
}
@ -191,7 +196,7 @@ class MyTeamComponent extends Component {
async vue_on_create() {
console.log('api', api)
const [my_team, lineup] = await Promise.all([api.get_my_team(), api.get_my_team_current_lineup()])
this.team_name = my_team.team_name
this.team_name = this._original_team_name = my_team.team_name
this.overall_data = await api.get_my_team_players()
this.bench_players = lineup.benched_players
this.starting_players = lineup.starting_players
@ -213,15 +218,36 @@ class MyTeamComponent extends Component {
}
mark_dirty() {
this.save_text = 'Unsaved changed'
this.save_text = 'Unsaved changes'
}
/**
* Fired when the team name changes. Marks the data as needing a save.
*/
watch_team_name() {
if ( this.team_name !== this._original_team_name )
this.mark_dirty()
}
async save_changes() {
this.save_text = 'Saving changes...'
setTimeout(() => {
// Save the team name
const team_save_result = await api.save_my_team({ team_name: this.team_name })
this.team_name = this._original_team_name = team_save_result.team_name
// Save the lineup
const lineup_data = {
starting_players: this.starting_players,
benched_players: this.bench_players,
}
const lineup_save_result = await api.save_my_team_lineup(lineup_data)
this.bench_players = lineup_save_result.benched_players
this.starting_players = lineup_save_result.starting_players
this.save_text = 'All changes saved.'
}, 2000)
this.update()
}
}

View File

@ -3,6 +3,10 @@ class API {
this.base_url = APP_BASE_PATH.replace('/app/', '/api/v1/')
}
async save_my_team(team_data) {
return this.post_request('my-team', team_data)
}
async get_my_team() {
return this.get_request('my-team')
}
@ -15,6 +19,26 @@ class API {
return this.get_request('my-team/lineup')
}
async save_my_team_lineup(lineup_data) {
return this.post_request('my-team/lineup', lineup_data)
}
async post_request(parts, data = {}) {
if ( !Array.isArray(parts) ) parts = [parts]
const url = this.build_url(...parts)
const result = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
return (await result.json()).data
}
async get_request(...parts) {
const url = this.build_url(...parts)
const result = await fetch(url)