Uppdating typescript tuff to allow it t build

This commit is contained in:
jmosrael@gmail.com
2024-05-29 15:47:45 -07:00
parent 65378473e0
commit 4eb5b22dc9
18 changed files with 287 additions and 198 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

47
frontend/dist/assets/index-a76aODRT.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -13,8 +13,8 @@
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Welcome to Vuetify 3</title>
<script type="module" crossorigin src="/assets/index-BJnL3x4A.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Iv1C9NNg.css">
<script type="module" crossorigin src="/assets/index-a76aODRT.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CouD1jr_.css">
</head>
<body>

View File

@@ -6,12 +6,11 @@
// Plugins
import vuetify from './vuetify'
import pinia from '../store'
import router from '../router'
// Types
import type { App } from 'vue'
export function registerPlugins(app: App) {
app.use(vuetify).use(router).use(pinia)
app.use(vuetify).use(router)
}

View File

@@ -1,5 +0,0 @@
# Store
Pinia stores are used to store reactive state and expose actions to mutate it.
Full documentation for this feature can be found in the Official [Pinia](https://pinia.esm.dev/) repository.

View File

@@ -1,8 +0,0 @@
// Utilities
import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', {
state: () => ({
//
})
})

View File

@@ -1,25 +0,0 @@
import { defineStore } from 'pinia'
export enum CharacterStatus {
Active = 'Active',
Inactive = 'Inactive',
Dead = 'Dead',
Retired = 'Retired'
}
export type Character = {
status: CharacterStatus
playerName: string
characterName: string
role: String
approvalDate: Date
}
export const useGameStore = defineStore('characters', {
state: () => {
return {
games: [{} as Character, {} as Character, {} as Character]
}
},
actions: {}
})

View File

@@ -1,38 +0,0 @@
import { defineStore } from 'pinia'
export enum GameStatus {
Complete = 'Complete',
Postponed = 'Postponed',
Pending = 'Pending'
}
export type Game = {
potato: string
alsoPotato: string
title: string
status: GameStatus
fix: boolean
datePosted: Date
dateRun: Date
gmPlayerName: string
charactersPicked: []
charactersApplied: []
}
export const useGameStore = defineStore('games', {
state: () => {
return {
count: 0,
games: [
{ potato: 'potato', alsoPotato: 'potato' } as Game,
{ potato: 'potato', alsoPotato: 'potato' } as Game,
{ potato: 'potato', alsoPotato: 'potato' } as Game
]
}
},
actions: {
increment() {
this.count++
}
}
})

View File

@@ -1,4 +0,0 @@
// Utilities
import { createPinia } from 'pinia'
export default createPinia()

61
frontend/src/types.ts Normal file
View File

@@ -0,0 +1,61 @@
export interface Game {
id: number
title: string
gamemaster: string
payoutEB: number
payoutIP: number
payoutLoot: string
status: string
postdate: number
pickedCharacter?: Character[]
appliedCharacter?: Character[]
}
export interface Character {
id: number
characterName: string
playerName: string
role: string
status: string
lastGame: number
}
export interface GameStats {
Complete: number
Postponed: number
Pending: number
Fixes: number
Events: number
AverageIP: number
AverageEB: number
TotalIP: number,
TotalEB: number
}
export interface GameCounts {
apps: number
picks: number
active: number
}
export interface GameCharacter {
characterId: number
characterName: string
gameId: number
gameTite: string
pickedCharacter?:Character
appliedCharacter?: Character
}
export interface RoleStats {
Fixer: GameCounts
Tech: GameCounts
Medtech: GameCounts
Media: GameCounts
Netrunner: GameCounts
Solo: GameCounts
Nomad: GameCounts
Exec: GameCounts
Lawman: GameCounts
Rocker: GameCounts
}

View File

@@ -33,22 +33,30 @@
</style>
<script setup lang="ts">
import { Character, Game } from '../types'
import GameTable from './GameTable.vue'
import { onMounted, watch, ref } from 'vue'
import { useRoute } from 'vue-router'
import axios from 'axios'
interface GameList {
played: Game[]
applied: Game[]
}
const route = useRoute()
const characterId = ref(route.params.characterId)
const character = ref({})
const games = ref({})
const character = ref<Character>({
id: 0, characterName: "", playerName: "", role: "", status: "", lastGame: 0
})
const games = ref<GameList>({played:[], applied: []})
const earnedEB = ref(0)
const earnedIP = ref(0)
const gamesPlayedCount = ref(0)
const gamesAppliedCount = ref(0)
const pickRate = ref(0)
const lastPlayedPostDate = ref({ played: [], applied: [] })
const lastPlayedPostDate = ref()
async function loadCharacterDetails() {
const characterResponse = await axios.get(`/api/character/${characterId.value}`)
@@ -61,7 +69,7 @@ async function loadCharacterDetails() {
}
}
function calculateDerivedEarnings(gamesPlayedList) {
function calculateDerivedEarnings(gamesPlayedList: Game[]) {
let runningEarnedEb = 0
let runningEarnedIp = 0
for (let game in gamesPlayedList) {
@@ -72,13 +80,13 @@ function calculateDerivedEarnings(gamesPlayedList) {
earnedIP.value = runningEarnedIp
}
function calculateDerivedGameStats(gamesPlayedList, gamesAppliedList) {
function calculateDerivedGameStats(gamesPlayedList: Game[], gamesAppliedList: Game[]) {
gamesPlayedCount.value = gamesPlayedList.length
gamesAppliedCount.value = gamesAppliedList.length
pickRate.value = (gamesPlayedList.length / gamesAppliedList.length) * 100
}
function calculateDerivedLastPlayedPostDate(gamesPlayedList) {
function calculateDerivedLastPlayedPostDate(gamesPlayedList: Game[]) {
if (gamesPlayedList.length === 0) {
lastPlayedPostDate.value = 'N/A'
} else {
@@ -88,7 +96,7 @@ function calculateDerivedLastPlayedPostDate(gamesPlayedList) {
}
}
watch(games, (newValue, oldValue) => {
watch(games, (newValue: GameList, oldValue: GameList) => {
calculateDerivedLastPlayedPostDate(newValue.played)
calculateDerivedEarnings(newValue.played)
calculateDerivedGameStats(newValue.played, newValue.applied)

View File

@@ -43,13 +43,15 @@
<style type="text/css"></style>
<script setup lang="ts">
import { onMounted, onCreated, ref } from 'vue'
import { Character } from '../types'
import { onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
const route = useRoute()
const router = useRouter()
const characters = ref({})
const characters = ref<Character[]>([])
const pageCount = ref(1)
const page = ref(1)
@@ -84,9 +86,9 @@ watch(route, (newValue, oldValue) => {
loadData()
})
let debounce = null
watch(filtervalue, (newFilter, oldFilter) => {
debounce = clearTimeout(debounce)
let debounce: ReturnType<typeof setTimeout>
watch(filtervalue, (newFilter: string, oldFilter: string) => {
clearTimeout(debounce)
debounce = setTimeout(() => {
router.replace({ query: { page: route.query.page, filter: newFilter } })
}, 500)
@@ -100,7 +102,7 @@ onMounted(async () => {
page.value = Number(route.query.page)
}
if (route.query.filter) {
filtervalue.value = route.query.filter
filtervalue.value = route.query.filter.toString()
}
loadData()
})

View File

@@ -1,53 +1,51 @@
<template>
<div class="game-title-box">
<v-container>
<h1>#{{ game.id }} - {{ game.title }}</h1>
</div>
<div class="gm-title-box">
<h2>GameMaster: {{ game.gamemaster }}</h2>
</div>
<div class="container">
<div class="d-flex flex-row">
<div class="result-box">
<h3>Picks</h3>
<div v-for="pick in picks">
{{ pick.pickedCharacter.playerName }} as {{ pick.characterName }}
<div class="container">
<div class="d-flex flex-row">
<div class="result-box">
<h3>Picks</h3>
<div v-for="pick in picks">
{{ pick.pickedCharacter!.playerName }} as {{ pick.characterName }}
</div>
</div>
<div class="result-box">
<h3>Payout</h3>
<div>{{ game.payoutEB }} EB</div>
<div>{{ game.payoutIP }} IP</div>
<div>{{ game.payoutLoot }}</div>
</div>
</div>
<div class="result-box">
<h3>Payout</h3>
<div>{{ game.payoutEB }} eb</div>
<div>{{ game.payoutIP }} IP</div>
<div>{{ game.payoutLoot }}</div>
</div>
</div>
</div>
<div class="container">
<div class="d-flex flex-row">
<div class="character-list">
<h3>{{ picks.length }} Character Picks</h3>
<v-data-table-virtual :headers="pickHeaders" :items="picks" height="500px" fixed-header>
<template v-slot:item.characterId="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterId }}</a>
</template>
<template v-slot:item.characterName="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterName }}</a>
</template>
</v-data-table-virtual>
<div class="container">
<div class="d-flex flex-row">
<div class="character-list">
<h3>{{ picks.length }} Character Picks</h3>
<v-data-table-virtual :headers="pickHeaders" :items="picks" height="500px" fixed-header>
<template v-slot:item.characterId="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterId }}</a>
</template>
<template v-slot:item.characterName="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterName }}</a>
</template>
</v-data-table-virtual>
</div>
<div class="character-list">
<h3>{{ apps.length }} Character Apps</h3>
<v-data-table-virtual :headers="appHeaders" :items="apps" height="500px" fixed-header>
<template v-slot:item.characterId="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterId }}</a>
</template>
<template v-slot:item.characterName="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterName }}</a>
</template>
</v-data-table-virtual>
</div>
</div>
<div class="character-list">
<h3>{{ apps.length }} Character Apps</h3>
<v-data-table-virtual :headers="appHeaders" :items="apps" height="500px" fixed-header>
<template v-slot:item.characterId="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterId }}</a>
</template>
<template v-slot:item.characterName="{ item }">
<a v-bind:href="`/#/characters/${item.characterId}`">{{ item.characterName }}</a>
</template>
</v-data-table-virtual>
</div>
</div>
</div>
</div></v-container
>
</template>
<style>
@@ -75,20 +73,24 @@
</style>
<script setup lang="ts">
import { Game, Character, GameCharacter } from '../types'
import { watch, ref } from 'vue'
import { VDataTable } from 'vuetify/components'
import { useRoute } from 'vue-router'
import axios from 'axios'
type ReadonlyHeaders = VDataTable['$props']['headers']
const route = useRoute()
const pickHeaders = [
const pickHeaders: ReadonlyHeaders = [
{ title: 'ID', align: 'start', key: 'characterId' },
{ title: 'Character', align: 'start', key: 'characterName' },
{ title: 'Status', align: 'start', key: 'pickedCharacter.status' },
{ title: 'Player', align: 'start', key: 'pickedCharacter.playerName' }
]
const appHeaders = [
const appHeaders: ReadonlyHeaders = [
{ title: 'ID', align: 'start', key: 'characterId' },
{ title: 'Character', align: 'start', key: 'characterName' },
{ title: 'Status', align: 'start', key: 'appliedCharacter.status' },
@@ -96,9 +98,18 @@ const appHeaders = [
]
const gameId = ref(route.params.gameId)
const game = ref({})
const picks = ref([])
const apps = ref([])
const game = ref<Game>({
id: 0,
title: "",
gamemaster: "",
payoutEB: 0,
payoutIP: 0,
payoutLoot: "",
status: "",
postdate: 0
})
const picks = ref<GameCharacter[]>([])
const apps = ref<GameCharacter[]>([])
loadGameDetails()

View File

@@ -47,20 +47,22 @@
</style>
<script setup lang="ts">
import { Game } from '../types'
import GameTable from './GameTable.vue'
import { onMounted, watch, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
const route = useRoute()
const router = useRouter()
const games = ref({})
const games = ref<Game[]>([])
let page = ref(1)
const pageCount = ref(1)
let count = 10
const filtervalue = ref('')
const filtervalue = ref<string>('')
async function loadData() {
const response = await axios.post('/api/game', {
@@ -87,14 +89,14 @@ watch(route, (newValue, oldValue) => {
}
if (route.query.filter) {
filtervalue.value = route.query.filter
filtervalue.value = route.query.filter.toString()
}
loadData()
})
let debounce = null
watch(filtervalue, (newFilter, oldFilter) => {
debounce = clearTimeout(debounce)
let debounce: ReturnType<typeof setTimeout>
watch(filtervalue, (newFilter: string, oldFilter: string) => {
clearTimeout(debounce)
debounce = setTimeout(() => {
router.replace({ query: { page: route.query.page, filter: newFilter } })
}, 500)
@@ -108,7 +110,7 @@ onMounted(async () => {
page.value = Number(route.query.page)
}
if (route.query.filter) {
filtervalue.value = route.query.filter
filtervalue.value = route.query.filter.toString()
}
loadData()
})

View File

@@ -15,12 +15,22 @@
<style></style>
<script setup lang="ts">
const props = defineProps(['gameList'])
import { Game } from '../types'
import { defineProps } from 'vue'
import { VDataTable } from 'vuetify/components'
const headers = [
type ReadonlyHeaders = VDataTable['$props']['headers']
interface Props {
gameList: Game[]
}
const props = defineProps<Props>()
const headers: ReadonlyHeaders = [
{ title: 'ID', align: 'start', key: 'id' },
{ title: 'Title', align: 'start', key: 'title' },
{ title: 'Status', aligasdfn: 'start', key: 'status' },
{ title: 'Status', align: 'start', key: 'status' },
{ title: 'Post Date', align: 'start', key: 'postdate' }
]
</script>

View File

@@ -92,31 +92,91 @@
</style>
<script setup lang="ts">
import { GameStats, RoleStats } from '../types'
import { onMounted, watch, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import Chart from 'chart.js/auto'
import axios from 'axios'
type ChartType = 'gametypes' | 'apps' | 'picks' | 'active'
const route = useRoute()
const router = useRouter()
const dateSelect = ref(-1)
const dateItems = buildDateItems()
const chartSelect = ref('active')
const chartSelect = ref<ChartType>('active')
const chartItems = [
{ title: 'Game Types', value: 'gametypes' },
{ title: 'Active Characters', value: 'active' },
{ title: 'Role Picks', value: 'picks' },
{ title: 'Role Applications', value: 'apps' }
]
const gameStats = ref<GameStats>({
Complete: 0,
Postponed: 0,
Pending: 0,
Fixes: 0,
Events: 0,
AverageIP: 0,
AverageEB: 0,
TotalIP: 0,
TotalEB: 0
})
const roleStats = ref<RoleStats>({
Fixer: {
apps: 0,
picks: 0,
active: 0
},
Tech: {
apps: 0,
picks: 0,
active: 0
},
Medtech: {
apps: 0,
picks: 0,
active: 0
},
Media: {
apps: 0,
picks: 0,
active: 0
},
Netrunner: {
apps: 0,
picks: 0,
active: 0
},
Solo: {
apps: 0,
picks: 0,
active: 0
},
Nomad: {
apps: 0,
picks: 0,
active: 0
},
Exec: {
apps: 0,
picks: 0,
active: 0
},
Lawman: {
apps: 0,
picks: 0,
active: 0
},
Rocker: {
apps: 0,
picks: 0,
active: 0
}
})
const gameStats = ref({})
const roleStats = ref({})
let chart
let chart: Chart<'pie', number[], string>
async function loadData() {
const gameStatsResponse = await axios.post('/api/serverstats/gamestats', {
@@ -155,7 +215,7 @@ function dateToMonthId(date: Date) {
return (date.getUTCFullYear() - 2023) * 12 + date.getUTCMonth()
}
function updateChart(stats, tag) {
function updateChart(stats: RoleStats, tag: ChartType) {
if (tag === 'gametypes') {
chart.data = {
labels: ['Standard', 'Postponed', 'Pending', 'Event', 'Fix'],
@@ -195,7 +255,7 @@ watch(roleStats, async (newValue, oldValue) => {
updateChart(newValue, chartSelect.value)
})
watch(chartSelect, async (newValue, oldValue) => {
watch(chartSelect, async (newValue: ChartType, oldValue: ChartType) => {
updateChart(roleStats.value, newValue)
})
@@ -207,7 +267,7 @@ onMounted(async () => {
dateSelect.value = Number(route.query.monthId)
}
loadData()
chart = new Chart(document.getElementById('piechart'), {
chart = new Chart(document.getElementById('piechart')! as HTMLCanvasElement, {
type: 'pie',
data: {
labels: [],