Skip to content

Commit

Permalink
640/leaderboard view page (#648)
Browse files Browse the repository at this point in the history
* feat: board path -> game

* feat: add new leaderboard view scaffold

- shows game name as header
- shows toggle-able info dropdown showing Leaderboard.Info
- if api returns a 404, renders the nuxt 404 page - This must be
  implemented globally and is out of scope of this PR

fix: does not render an info button if no info blurb exists ('')

fix: simply v-if for showing info switch

fix: do not use <switch> - opt for <button>

* fix: lint error on leaderboard being non-nullable

* fix: test components

* WIP: add pr changes to view leaderboards

- update getLeaderboards -> listLeaderboards
- make default leaderboard returns use info: ''
- use correct components in some tests

* fix: check error value statusCode is 404 when status code is 404

chore: remove comment

* fix: restore slug on test after each

* fix: again use correct restore all mocks function

* fix: destructure route

* fix: rebind error - vue already sets it and throws proxy error

* fix: Page -> Board Not Found
  • Loading branch information
Eein authored Dec 6, 2024
1 parent 0394ed3 commit 17c3371
Show file tree
Hide file tree
Showing 21 changed files with 189 additions and 454 deletions.
2 changes: 1 addition & 1 deletion components/blocks/Landing/Landing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import LandingLeaderboards from './LandingLeaderboards.vue'
const mockSuccessGetLeaderboards = vi.fn(() => Promise.resolve({ ok: true }))
vi.mock('lib/api/Leaderboards', () => ({
Leaderboards: function Leaderboards() {
this.getLeaderboards = mockSuccessGetLeaderboards
this.listLeaderboards = mockSuccessGetLeaderboards
},
}))

Expand Down
14 changes: 5 additions & 9 deletions components/blocks/Landing/LandingLeaderboards.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { mountSuspended } from '@nuxt/test-utils/runtime'
import Landing from './LandingLeaderboards.vue'
import LandingLeaderboards from './LandingLeaderboards.vue'
import type { LeaderboardViewModel } from '~/lib/api/data-contracts'

const games: LeaderboardViewModel[] = [
{
id: 1,
name: 'Getting Over It With Bennet Foddy',
slug: 'slug-2',
info: null,
info: '',
createdAt: '2024-11-02T22:11:08+0000',
updatedAt: '2024-11-02T22:11:08+0000',
deletedAt: null,
Expand All @@ -17,7 +17,7 @@ const games: LeaderboardViewModel[] = [
id: 2,
name: 'Getting Over It With Bennet Foddy',
slug: 'slug-2',
info: null,
info: '',
createdAt: '2024-11-02T22:11:08+0000',
updatedAt: '2024-11-02T22:11:08+0000',
deletedAt: null,
Expand All @@ -27,7 +27,7 @@ const games: LeaderboardViewModel[] = [
id: 3,
name: 'Getting Over It With Bennet Foddy',
slug: 'slug-3',
info: null,
info: '',
createdAt: '2024-11-02T22:11:08+0000',
updatedAt: '2024-11-02T22:11:08+0000',
deletedAt: null,
Expand All @@ -36,12 +36,8 @@ const games: LeaderboardViewModel[] = [
]

describe('LandingLeaderboards Component', () => {
afterEach(() => {
vi.restoreAllMocks()
})

it('should render without crashing', async () => {
const wrapper = await mountSuspended(Landing, {
const wrapper = await mountSuspended(LandingLeaderboards, {
props: {
leaderboards: games,
},
Expand Down
2 changes: 1 addition & 1 deletion components/blocks/Landing/LandingLeaderboards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defineProps<LandingLeaderboardsProps>()
class="mb-2 h-full content-center rounded-lg bg-gray-200 p-8 text-blue-500 underline hover:cursor-pointer"
:to="
localePath({
name: 'board-slug',
name: 'game-slug',
params: { slug: leaderboard.slug },
})
"
Expand Down
33 changes: 0 additions & 33 deletions components/blocks/LeaderboardInfo/Desktop/Desktop.test.ts

This file was deleted.

141 changes: 0 additions & 141 deletions components/blocks/LeaderboardInfo/Desktop/Desktop.vue

This file was deleted.

53 changes: 18 additions & 35 deletions components/blocks/LeaderboardInfo/LeaderboardInfo.test.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,30 @@
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { getByTestId } from 'root/testUtils'
import LeaderboardInfo from './LeaderboardInfo.vue'
import type { LeaderboardViewModel } from '~/lib/api/data-contracts'

describe('<LeaderboardInfo />', () => {
async function getLeaderboardInfoWrapper() {
return await mountSuspended(LeaderboardInfo, {
const game: LeaderboardViewModel = {
id: 1,
name: 'Getting Over It With Bennet Foddy',
slug: 'slug-2',
info: 'Something special',
createdAt: '2024-11-02T22:11:08+0000',
updatedAt: '2024-11-02T22:11:08+0000',
deletedAt: null,
categories: [],
}

describe('LeaderboardInfo Component', () => {
it('should render without crashing', async () => {
const wrapper = await mountSuspended(LeaderboardInfo, {
props: {
leaderboard: {
categories: [],
id: 1,
name: 'Stuck in the Train Simulator 2',
slug: 'stuck-in-the-train-sim-2',
},
leaderboard: game,
},
})
}

afterEach(() => {
vi.restoreAllMocks()
vi.unstubAllGlobals()
})

it('should render without crashing', async () => {
const wrapper = await getLeaderboardInfoWrapper()
expect(wrapper.isVisible()).toBe(true)
})

it('should render <Desktop /> if device width is large', async () => {
vi.stubGlobal('innerWidth', 1980)
const wrapper = await getLeaderboardInfoWrapper()
expect(wrapper.html()).toContain('Guides')
})

it('should render <Mobile /> if device width is small', async () => {
vi.stubGlobal('innerWidth', 600)
const wrapper = await getLeaderboardInfoWrapper()
expect(wrapper.html()).toContain('Submit Run')
})
const header = wrapper.get('div#leaderboard-show-header h1')

// TODO: The follow event doesn't trigger in the test, somehow
it.skip('should emit event when the Follow Button is triggered', async () => {
const wrapper = await getLeaderboardInfoWrapper()
await getByTestId(wrapper, 'child').trigger('follow')
expect(wrapper.emitted().follow).toBeTruthy()
expect(header.text()).toContain(game.name)
})
})
60 changes: 13 additions & 47 deletions components/blocks/LeaderboardInfo/LeaderboardInfo.vue
Original file line number Diff line number Diff line change
@@ -1,55 +1,21 @@
<script setup lang="ts">
import { useThrottleFn } from '@vueuse/core'
import resolveConfig from 'tailwindcss/resolveConfig'
import { ref } from 'vue'
import tailwindConfig from 'root/tailwind.config'
import Desktop from './Desktop/Desktop.vue'
import Mobile from './Mobile/Mobile.vue'
import type { LeaderboardViewModel } from 'lib/api/data-contracts'
export interface LeaderboardInfoProps {
<script lang="ts" setup>
import type { LeaderboardViewModel } from '~/lib/api/data-contracts'
import LeaderboardInfoAccordion from './LeaderboardInfoAccordion.vue'
interface LeaderboardInfoProps {
leaderboard: LeaderboardViewModel
}
// TODO: Remove this. Get from model instead.
const todoPlatforms = ['PS4', 'PC', 'XboxSeriesX']
// TODO: Implement listeners
const emit = defineEmits<{
(event: 'follow', leaderboardId: number): void
}>()
const mobileWidth = parseInt(
resolveConfig(tailwindConfig).theme.screens.sm.replace('px', ''),
10,
)
const isMobile = ref(window.innerWidth <= mobileWidth)
function checkIsMobile() {
isMobile.value = window.innerWidth <= mobileWidth
}
window.addEventListener('resize', useThrottleFn(checkIsMobile, 20))
defineProps<LeaderboardInfoProps>()
</script>

<template>
<Mobile
v-if="isMobile.valueOf()"
data-testid="child"
:leaderboard="leaderboard"
:todo-platforms="todoPlatforms"
@follow="emit('follow', leaderboard.id)"
/>
<Desktop
v-else
data-testid="child"
:leaderboard="leaderboard"
:todo-platforms="todoPlatforms"
@follow="emit('follow', leaderboard.id)"
/>
<div class="flex w-full flex-col rounded border border-gray-300 p-5">
<div id="leaderboard-show-header" class="mb-4 bg-gray-200 p-4">
<h1 class="mb-4 text-xl font-bold">{{ leaderboard.name }}</h1>
<LeaderboardInfoAccordion
v-if="leaderboard?.info"
:info="leaderboard.info"
/>
</div>
</div>
</template>

<style lang="postcss" scoped></style>
Loading

0 comments on commit 17c3371

Please sign in to comment.