Skip to content

Commit

Permalink
1) Added new AuctionEar components for playing a game that slams
Browse files Browse the repository at this point in the history
Heardle against an Adwords Dutch auction and produces a fun party game.
2) Added test coverage for components.
3) Adjusted test setup and dependencies for the `AudioPlayer`.
  • Loading branch information
RobSpectre committed May 19, 2022
1 parent dc28b05 commit 3b21a60
Show file tree
Hide file tree
Showing 15 changed files with 956 additions and 4 deletions.
5 changes: 4 additions & 1 deletion jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import { mocks } from './tests/test-utils'
/* eslint no-undef: "off" */
global.Audio = jest.fn().mockImplementation(() => ({
pause: mocks.Audio.pause,
play: mocks.Audio.play
play: mocks.Audio.play,
addEventListener: mocks.Audio.addEventListener,
currentTime: 12,
duration: 16
}))
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore src",
"lint:fix": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ./",
"lint:fix": "eslint --ext .js,.vue --ignore-path .gitignore --fix ./",
"test": "jest",
"test:inspect": "node --inspect-brk node_modules/.bin/jest --runInBand"
},
Expand Down
Binary file added public/images/auctionear_header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sounds/wrong_sound.mp3
Binary file not shown.
51 changes: 51 additions & 0 deletions src/components/AuctionEar/AuctionEarBid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template lang='pug'>
.flex.flex-col.mx-32.rounded-lg.shadow-lg.overflow-hidden.text-left
.flex-shrink-0
img.h-48.m-0.w-full.clear-reveal.object-cover(:src='image' alt='')
.flex-1.bg-white.p-6.flex.flex-col.justify-between
.flex-1
span.block.mt-2.text-xl.leading-7.font-semibold.text-gray-900
| {{ prompt }}
.my-4.text-center
input.shadow.appearance-none.border.rounded.py-2.px-3.text-gray-700.leading-tight(
class='w-1/3 focus:outline-none focus:shadow-outline' type='text'
:placeholder='placeholderInput'
v-model='currentInput'
v-on:keydown.enter='emitInput(currentPlayer, currentInput)')
.flex-1.bg-green.p-6.flex.flex-col.justify-between
span.text-2xl.leading-7.font-semibold.text-white
| {{ currentPlayer.name }}
</template>

<script>
export default {
name: 'AuctionEarBid',
props: {
currentPlayer: Object,
image: {
type: String,
default: '/images/auctionear_header.png'
},
prompt: {
type: String,
default: 'What is your bid?'
},
placeholderInput: {
type: String,
default: 'Bid'
}
},
data () {
return {
currentInput: ''
}
},
methods: {
emitInput (player, input) {
this.$emit('output', { player: player, value: input })
this.currentInput = ''
}
}
}
</script>
46 changes: 46 additions & 0 deletions src/components/AuctionEar/AuctionEarGuess.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template lang='pug'>
.flex.flex-col.mx-32.rounded-lg.shadow-lg.overflow-hidden.text-left
.flex-shrink-0
img.h-48.m-0.w-full.clear-reveal.object-cover(:src='image' alt='')
.flex-1.bg-white.p-6.flex.flex-col.justify-between
.flex-1
span.block.mt-2.text-xl.leading-7.font-semibold.text-gray-900
| {{ prompt }}
.my-4.text-center.flex.flex-col.justify-between.items-center
button.actionButton(
v-for='(item, index) in items'
@click='emitGuess(currentPlayer, index)'
) {{ item.name }} {{ item.emoji }}
.flex-1.bg-green.p-6.flex.flex-col.justify-between
span.text-2xl.leading-7.font-semibold.text-white
| {{ currentPlayer.name }}
</template>

<script>
export default {
name: 'AuctionEarGuess',
props: {
items: Array,
currentPlayer: Object,
prompt: {
type: String,
default: 'What is your guess?'
},
image: {
type: String,
default: '/images/auctionear_header.png'
}
},
methods: {
emitGuess (player, index) {
this.$emit('guess', { player: player, value: index })
}
}
}
</script>

<style lang="scss">
.actionButton {
@apply inline-flex justify-center px-6 py-3 border border-transparent leading-6 font-medium rounded-md text-white text-2xl uppercase bg-darkgray transition ease-in-out duration-150 my-2 hover:bg-slate-300 focus:outline-none focus:border-slate-300 active:bg-slate-300;
}
</style>
234 changes: 234 additions & 0 deletions src/components/AuctionEar/AuctionEarRound.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<template lang='pug'>
GameContentWithSidebar(v-if='game.players.length > 0')
template(v-slot:content)
.flex.flex-initial.grid.grid-cols-3.gap-4.p-4.w-full
.col-span-3
AudioPlayer(
:src='src'
:chunks='chunks',
:chunkIndex='chunkIndex'
:chunkEvenly='chunkEvenly'
)
.flex.flex-col
Ladder(
:items='bids'
:ascending='true'
)
.pt-2
CounterBox(
label='Pot Total'
:counter='prizeValue'
)
.col-span-2.flex.grow.flex-col
AuctionEarBid(
v-if="phase === 'bid'"
:currentPlayer='currentPlayer'
@output='handleBid'
)
AuctionEarGuess(
v-if="phase === 'guess'"
:currentPlayer='currentGuesser'
:items='items'
@guess='handleGuess'
)
WinnerCard(
v-if='winners.length > 0'
:winners='winners'
:answerName='answer'
answerValue='the song'
)
LoserCard(
v-if='losers.length > 0'
:losers='losers'
:answerName='answer'
answerValue='the song'
)
</template>

<script>
import { mapState, mapActions, mapGetters } from 'pinia'
import { useGameStore } from '@/store'
import GameContentWithSidebar from '@/components/base/GameContentWithSidebar.vue'
import ActionButton from '@/components/base/ActionButton.vue'
import AudioPlayer from '@/components/AuctionEar/AudioPlayer.vue'
import Ladder from '@/components/AuctionEar/Ladder.vue'
import AuctionEarBid from '@/components/AuctionEar/AuctionEarBid.vue'
import AuctionEarGuess from '@/components/AuctionEar/AuctionEarGuess.vue'
import WinnerCard from '@/components/base/WinnerCard.vue'
import LoserCard from '@/components/base/LoserCard.vue'
import CounterBox from '@/components/base/CounterBox.vue'
export default {
name: 'AuctionEarRound',
components: {
GameContentWithSidebar,
ActionButton,
AudioPlayer,
Ladder,
AuctionEarBid,
AuctionEarGuess,
WinnerCard,
LoserCard,
CounterBox
},
props: {
src: String,
answer: String,
chunks: Number,
ascending: {
type: Boolean,
default: true
},
awardTotalPot: {
type: Boolean,
default: false
},
chunkEvenly: {
type: Boolean,
default: false
}
},
data () {
return {
bids: [],
phases: ['bid', 'guess'],
phaseIndex: 0,
chunkIndex: 0,
guessIndex: 0,
complete: false,
prizeValue: 0,
items: [
{ name: 'Right', emoji: '🎊️' },
{ name: 'Wrong', emoji: '👎️' }
],
winners: [],
losers: []
}
},
computed: {
...mapState(useGameStore, ['game']),
...mapGetters(useGameStore, ['getPlayer']),
currentPlayer () {
return this.game.players[this.game.playerIndex]
},
currentGuesser () {
return this.getPlayer(this.bids[this.guessIndex].name)
},
phase () {
return this.phases[this.phaseIndex]
}
},
methods: {
orderedBids () {
const ordered = []
this.bids.forEach((bid) => {
ordered.push(bid)
})
if (this.ascending === false) {
return ordered.sort((a, b) => a.value - b.value).reverse()
} else {
return ordered.sort((a, b) => a.value - b.value)
}
},
handleBid (event) {
this.bids.push({
name: event.player.name,
value: parseInt(event.value)
})
this.nextPlayer()
},
handleGuess (event) {
if (event.value === 0) {
this.awardWinner(event.player.name)
} else {
this.increasePlayerScore(event.player.name, -this.bids[this.guessIndex].value)
this.prizeValue = this.prizeValue + this.bids[this.guessIndex].value
this.bids[this.guessIndex].value = 0
const audio = new Audio('/sounds/wrong_sound.mp3')
audio.volume = 0.2
audio.play()
this.nextGuess()
}
},
nextPlayer () {
this.increasePlayerIndex()
if (this.game.playerIndex === this.game.playerButton) {
this.phaseIndex++
this.bids = this.orderedBids()
this.bids[this.guessIndex].active = true
}
},
nextChunk () {
this.phaseIndex = 0
this.guessIndex = 0
this.bids = []
this.chunkIndex++
this.increasePlayerButton()
if (this.chunkIndex >= this.chunks) {
this.complete = true
this.awardLosers()
}
},
nextGuess () {
if (this.bids[this.guessIndex + 1] === undefined) {
this.guessIndex = 0
this.phaseIndex++
} else {
this.guessIndex++
this.bids[this.guessIndex].active = true
}
if (this.phases[this.phaseIndex] === undefined) {
this.nextChunk()
}
},
awardWinner (playerName) {
this.increasePlayerScore(playerName, this.bids[this.guessIndex].value)
if (this.awardTotalPot === true) {
this.increasePlayerScore(playerName, -this.bids[this.guessIndex].value)
const bidValues = this.bids.map(bid => bid.value)
const bidSum = bidValues.reduce((partialSum, a) => partialSum + a, 0)
this.increasePlayerScore(playerName, this.prizeValue + bidSum)
} else {
this.increasePlayerScore(playerName, this.prizeValue)
}
const audio = new Audio(this.src)
audio.volume = 0.5
audio.play()
this.winners.push(playerName)
this.complete = true
},
awardLosers () {
const audio = new Audio('/sounds/loser_sound.mp3')
audio.volume = 0.2
audio.play()
this.losers = this.game.players.map(player => player.name)
},
...mapActions(useGameStore,
['increasePlayerButton',
'increasePlayerIndex',
'increasePlayerScore'])
}
}
</script>
Loading

0 comments on commit 3b21a60

Please sign in to comment.