Skip to content

Commit

Permalink
fix: cleanup queue page (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
garrappachc authored Dec 10, 2024
1 parent 72ac3c4 commit 3749d6d
Show file tree
Hide file tree
Showing 24 changed files with 252 additions and 218 deletions.
2 changes: 2 additions & 0 deletions src/queue/apply-map-cooldown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { configuration } from '../configuration'
import { collections } from '../database/collections'
import { logger } from '../logger'

export async function applyMapCooldown(map: string) {
logger.trace({ map }, 'queue.applyMapCooldown()')
await collections.maps.updateMany(
{ name: { $ne: map }, cooldown: { $gt: 0 } },
{ $inc: { cooldown: -1 } },
Expand Down
2 changes: 2 additions & 0 deletions src/queue/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { environment } from '../environment'
import { logger } from '../logger'
import { queueConfigs } from './configs'

logger.info(`using queue config: ${environment.QUEUE_CONFIG}`)
export const config = queueConfigs[environment.QUEUE_CONFIG]
2 changes: 1 addition & 1 deletion src/queue/get-map-winner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function getMapWinner(): Promise<string> {
},
])
.toArray()
logger.trace({ mapsWithVotes })
logger.trace({ mapsWithVotes }, 'queue.getMapWinner()')
const maxVotes = maxBy(mapsWithVotes, r => r.votes)?.votes ?? 0
const mapsWithMaxVotes = mapsWithVotes.filter(m => m.votes === maxVotes)
return sample(mapsWithMaxVotes)!.name
Expand Down
8 changes: 4 additions & 4 deletions src/queue/join.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import { mutex } from './mutex'

export async function join(slotId: number, steamId: SteamId64): Promise<QueueSlotModel[]> {
return await mutex.runExclusive(async () => {
logger.trace({ steamId, slotId }, `join queue`)
logger.trace({ steamId, slotId }, `queue.join()`)
const player = await collections.players.findOne({ steamId })
if (!player) {
throw new Error(`player does not exist: ${steamId}`)
}

// if (!player.hasAcceptedRules) {
// throw new Error(`player has not accepted rules`)
// }
if (!player.hasAcceptedRules) {
throw new Error(`player has not accepted rules`)
}

if (player.activeGame) {
throw new Error(`player has active game`)
Expand Down
2 changes: 1 addition & 1 deletion src/queue/kick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { preReady } from './pre-ready'

export async function kick(...steamIds: SteamId64[]): Promise<QueueSlotModel[]> {
return await mutex.runExclusive(async () => {
logger.debug({ steamIds }, 'kick from queue')
logger.trace({ steamIds }, 'queue.kick()')
const state = await getState()
if (state === QueueState.launching) {
throw new Error('invalid queue state')
Expand Down
2 changes: 1 addition & 1 deletion src/queue/leave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { preReady } from './pre-ready'

export async function leave(steamId: SteamId64): Promise<QueueSlotModel> {
return await mutex.runExclusive(async () => {
logger.debug({ steamId }, 'leave queue')
logger.trace({ steamId }, 'queue.leave()')
const state = await getState()
if (state === QueueState.launching) {
throw new Error('invalid queue state')
Expand Down
2 changes: 1 addition & 1 deletion src/queue/mark-as-friend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export async function markAsFriend(
target: SteamId64 | null,
): Promise<QueueSlotModel | null> {
return await mutex.runExclusive(async () => {
logger.info(`marking ${source} as friend of ${target}`)
logger.trace({ source, target }, `queue.markAsFriend()`)

const queueState = await getState()
if (queueState === QueueState.launching) {
Expand Down
3 changes: 1 addition & 2 deletions src/queue/ready-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import { mutex } from './mutex'

export async function readyUp(steamId: SteamId64): Promise<QueueSlotModel> {
return await mutex.runExclusive(async () => {
logger.trace({ steamId }, 'queue.readyUp()')
const state = await getState()
if (state !== QueueState.ready) {
throw new Error('wrong queue state')
}

logger.info(`player ${steamId} ready`)

const slot = await collections.queueSlots.findOneAndUpdate(
{ player: steamId },
{ $set: { ready: true } },
Expand Down
1 change: 1 addition & 0 deletions src/queue/reset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getState } from './get-state'
import { mapPool } from './map-pool'

export async function reset() {
logger.trace('queue.reset()')
const slots = generateEmptyQueue()
await collections.queueSlots.deleteMany({})
await collections.queueSlots.insertMany(slots)
Expand Down
2 changes: 2 additions & 0 deletions src/queue/set-state.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { collections } from '../database/collections'
import { QueueState } from '../database/models/queue-state.model'
import { events } from '../events'
import { logger } from '../logger'
import { mutex } from './mutex'

export async function setState(state: QueueState) {
return await mutex.runExclusive(async () => {
logger.trace({ state }, 'queue.setState()')
await collections.queueState.updateOne({}, { $set: { state } })

if (state === QueueState.ready) {
Expand Down
2 changes: 2 additions & 0 deletions src/queue/unready.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { collections } from '../database/collections'
import type { QueueSlotModel } from '../database/models/queue-slot.model'
import { events } from '../events'
import { logger } from '../logger'
import type { SteamId64 } from '../shared/types/steam-id-64'
import { mutex } from './mutex'

export async function unready(...steamIds: SteamId64[]): Promise<QueueSlotModel[]> {
return await mutex.runExclusive(async () => {
logger.trace({ steamIds }, 'queue.unready()')
const slots: QueueSlotModel[] = []
for (const steamId of steamIds) {
const slot = await collections.queueSlots.findOneAndUpdate(
Expand Down
183 changes: 89 additions & 94 deletions src/queue/views/html/queue-slot.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { collections } from '../../../database/collections'
import type { PlayerModel } from '../../../database/models/player.model'
import type { QueueSlotModel } from '../../../database/models/queue-slot.model'
import {
IconHeart,
Expand All @@ -10,7 +9,8 @@ import {
} from '../../../html/components/icons'
import type { SteamId64 } from '../../../shared/types/steam-id-64'

enum MarkAsFriendButtonState {
const enum MarkAsFriendButtonState {
none,
enabled,
disabled, // marked by another player
selected, // marked by me
Expand All @@ -19,37 +19,7 @@ enum MarkAsFriendButtonState {
export async function QueueSlot(props: { slot: QueueSlotModel; actor?: SteamId64 | undefined }) {
let slotContent = <></>
if (props.slot.player) {
const player = await collections.players.findOne({ steamId: props.slot.player })
if (!player) {
throw new Error(`player does not exist: ${props.slot.player}`)
}

let markAsFriendButtonState: MarkAsFriendButtonState | undefined = undefined

if (props.actor) {
const actorsSlot = await collections.queueSlots.findOne({ player: props.actor })
if (actorsSlot?.canMakeFriendsWith?.includes(props.slot.gameClass)) {
const friendship = await collections.queueFriends.findOne({
target: props.slot.player,
})
if (friendship === null) {
markAsFriendButtonState = MarkAsFriendButtonState.enabled
} else if (friendship.source === props.actor) {
markAsFriendButtonState = MarkAsFriendButtonState.selected
} else {
markAsFriendButtonState = MarkAsFriendButtonState.disabled
}
}
}

slotContent = (
<PlayerInfo
player={player}
isActorsSlot={props.actor === props.slot.player}
ready={props.slot.ready}
markAsFriendButtonState={markAsFriendButtonState}
/>
)
slotContent = <PlayerInfo {...props} />
} else if (props.actor) {
const actor = await collections.players.findOne({ steamId: props.actor })
if (!actor) {
Expand All @@ -61,7 +31,6 @@ export async function QueueSlot(props: { slot: QueueSlotModel; actor?: SteamId64
end: { $gt: new Date() },
})
const disabled = Boolean(actor.activeGame) || activeBans > 0

slotContent = <JoinButton slotId={props.slot.id} disabled={disabled} />
}

Expand All @@ -82,80 +51,106 @@ function JoinButton(props: { slotId: number; disabled: boolean }) {
class="join-queue-button"
name="join"
value={`${props.slotId}`}
aria-label={`Join queue on slot ${props.slotId}`}
disabled={props.disabled}
>
<span class="sr-only">Join queue on slot {props.slotId}</span>
{props.disabled ? <IconLock /> : <IconPlus />}
</button>
)
}

function PlayerInfo(props: {
player: PlayerModel
isActorsSlot: boolean
ready: boolean
markAsFriendButtonState: MarkAsFriendButtonState | undefined
}) {
let slotButton = <></>
if (props.isActorsSlot && !props.ready) {
slotButton = (
<button class="leave-queue-button" name="leave" value="" aria-label="Leave queue">
async function PlayerInfo(props: { slot: QueueSlotModel; actor?: SteamId64 | undefined }) {
if (!props.slot.player) {
return <></>
}

const player = await collections.players.findOne({ steamId: props.slot.player })
if (!player) {
throw new Error(`player does not exist: ${props.slot.player}`)
}

let slotActionButton = <></>
if (props.actor === props.slot.player && !props.slot.ready) {
slotActionButton = (
<button class="leave-queue-button" name="leave" value="">
<IconMinus />
<span class="sr-only">Leave queue</span>
</button>
)
} else if (props.markAsFriendButtonState !== undefined) {
slotButton = (
<button
class={[
'mark-as-friend-button',
props.markAsFriendButtonState === MarkAsFriendButtonState.selected && 'selected',
]}
disabled={props.markAsFriendButtonState === MarkAsFriendButtonState.disabled}
name="markasfriend"
value={
props.markAsFriendButtonState === MarkAsFriendButtonState.selected
? ''
: props.player.steamId
}
aria-label={
props.markAsFriendButtonState === MarkAsFriendButtonState.selected
? 'Unfriend'
: 'Mark as friend'
}
>
{props.markAsFriendButtonState === MarkAsFriendButtonState.selected ? (
<IconHeartFilled />
) : (
<IconHeart />
)}
</button>
)
} else {
slotActionButton = <MarkAsFriendButton {...props} />
}

return (
<div
class={[
'flex flex-1 flex-row items-center justify-center p-2',
!props.isActorsSlot && !props.ready && 'taken',
props.isActorsSlot && 'my-slot',
props.ready && 'ready',
]}
>
<img
src={props.player.avatar.medium}
width="64"
height="64"
alt={`${props.player.name}'s name`}
class="h-[42px] w-[42px] rounded"
/>
<a
class="flex-1 overflow-hidden whitespace-nowrap text-center text-xl font-bold text-abru-dark-3 hover:underline"
href={`/players/${props.player.steamId}`}
safe
>
{props.player.name}
<div class="player-info" data-player-ready={`${props.slot.ready}`}>
<img src={player.avatar.medium} width="64" height="64" alt={`${player.name}'s name`} />
<a href={`/players/${player.steamId}`} safe>
{player.name}
</a>
<div class="w-[42px] px-1">{slotButton}</div>
{slotActionButton}
</div>
)
}

async function MarkAsFriendButton(props: { slot: QueueSlotModel; actor?: SteamId64 | undefined }) {
const markAsFriendButtonState = await determineMarkAsFriendButtonState(props.slot, props.actor)
if (markAsFriendButtonState === MarkAsFriendButtonState.none) {
return <></>
}

return (
<label class="mark-as-friend-button">
<input
type="checkbox"
id={`mark-as-friend-${props.slot.id}`}
disabled={markAsFriendButtonState === MarkAsFriendButtonState.disabled}
checked={markAsFriendButtonState === MarkAsFriendButtonState.selected}
ws-send
hx-vals={JSON.stringify({
markasfriend:
markAsFriendButtonState === MarkAsFriendButtonState.selected
? null
: props.slot.player!,
})}
hx-trigger="change"
/>
<span class="sr-only">Mark as friend</span>
<div class="mark">
{markAsFriendButtonState === MarkAsFriendButtonState.selected ? (
<IconHeartFilled />
) : (
<IconHeart />
)}
</div>
</label>
)
}

async function determineMarkAsFriendButtonState(
slot: QueueSlotModel,
actor?: SteamId64,
): Promise<MarkAsFriendButtonState> {
if (!slot.player) {
return MarkAsFriendButtonState.none
}

if (!actor) {
return MarkAsFriendButtonState.none
}

const actorsSlot = await collections.queueSlots.findOne({ player: actor })
if (actorsSlot?.canMakeFriendsWith?.includes(slot.gameClass)) {
const friendship = await collections.queueFriends.findOne({
target: slot.player,
})
if (friendship === null) {
return MarkAsFriendButtonState.enabled
} else if (friendship.source === actor) {
return MarkAsFriendButtonState.selected
} else {
return MarkAsFriendButtonState.disabled
}
}

return MarkAsFriendButtonState.none
}
Loading

0 comments on commit 3749d6d

Please sign in to comment.