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

View File

@@ -8,8 +8,6 @@ import { addCharacterApis } from './characterservice'
const app = express()
const jsonParser = json()
const fp = new FilterParser()
const obp = new OrderByParser()
const port = 3001
app.get('/', (req, res) => {

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: [],