Skip to content

Commit

Permalink
newui: add demo listing to player details
Browse files Browse the repository at this point in the history
  • Loading branch information
yoyosan committed Oct 28, 2023
1 parent 46e0b94 commit d3a7b10
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 44 deletions.
20 changes: 20 additions & 0 deletions src/newui/src/api/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ApiRequestParams } from '@/types/api';
import { DemoApiResponse, DemoStats } from '@/types/demo';

import { api } from 'boot/axios';

export const DemoApi = {
list: async (steamId: string, params: ApiRequestParams = { limit: 50, offset: 0 }): Promise<DemoApiResponse> => {
const { data } = await api.get<DemoApiResponse>(`player/${steamId}/demos`, {
params,
});

return data;
},

details: async (demoId: number): Promise<DemoStats> => {
const { data } = await api.get<DemoStats>(`demo/${demoId}/stats/`);

return data;
},
};
2 changes: 1 addition & 1 deletion src/newui/src/api/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { PlayerApiResponse, PlayerInfoResponse, PlayerStats, PlayerTeamMate
import { api } from 'boot/axios';

export const PlayerApi = {
get: async (params: ApiRequestParams = { limit: 50, offset: 0 }): Promise<PlayerApiResponse> => {
list: async (params: ApiRequestParams = { limit: 50, offset: 0 }): Promise<PlayerApiResponse> => {
const { data } = await api.get<PlayerApiResponse>('players', {
params,
});
Expand Down
102 changes: 100 additions & 2 deletions src/newui/src/components/Player/Demos.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,105 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { now } from 'lodash';
import { date } from 'quasar';
import { ref } from 'vue';
import { DEMO_TYPE_IMAGES } from 'src/constants/demos';
import { RANKS } from 'src/constants/ranks';
import { ApiRequestParams } from '@/types/api';
import { DataTableHeader } from '@/types/dataTable';
import { DemoResponse } from '@/types/demo';
import { DemoApi } from 'src/api/demo';
import { Format } from 'src/utils/formatters';
import DataTable from 'components/common/DataTable.vue';
/* ====================== Data ====================== */
const props = defineProps<{
steamId: string;
}>();
const tableRef = ref();
const columns: DataTableHeader[] = [
{ label: 'Date', name: 'timestamp', align: 'left', style: 'width: 75px' },
// { label: 'Type', name: 'type' },
{ label: 'Rank', name: 'mmRankUpdate' },
{ label: 'Map', name: 'map' },
{ label: 'Score', name: 'score' },
{ label: 'K', name: 'kills' },
{ label: 'A', name: 'assists' },
{ label: 'D', name: 'deaths' },
{ label: 'KDD', name: 'kdd' },
{ label: 'ADR', name: 'adr' },
];
/* ====================== Methods ====================== */
const getDemos = async ({ limit, offset, orderBy }: ApiRequestParams) => {
const { demos, demoCount } = await DemoApi.list(props.steamId, { ...{ limit, offset, orderBy } });
return {
results: demos,
count: demoCount,
};
};
const formatDate = (timestamp: number) => {
const timestampYear = date.formatDate(timestamp * 1000, 'YYYY');
const currentYear = date.formatDate(now(), 'YYYY');
const dateFormat = timestampYear === currentYear ? 'D MMM, H:mm' : 'D MMM YY, H:mm';
return date.formatDate(timestamp * 1000, dateFormat);
};
</script>

<template>
<q-page class=""> </q-page>
<q-page class="">
<DataTable ref="tableRef" :columns="columns" entityName="demo" :apiCall="getDemos" rowsPerPage="25">
<template #timestamp="item: DemoResponse">
{{ formatDate(item.timestamp) }}
</template>

<template #type="item: DemoResponse">
<q-img v-if="item.type" :src="DEMO_TYPE_IMAGES[item.type] as string" width="50px" />
</template>

<template #mmRankUpdate="{ mmRankUpdate }: DemoResponse">
<q-img
fit="fill"
class="my-1 rounded"
width="45px"
height="19px"
:src="`images/ranks/${(mmRankUpdate && mmRankUpdate.rankNew) ?? 0}.png`"
>
<q-tooltip class="bg-sky-500/95 text-sm shadow-4 text-black" anchor="top middle" self="bottom middle">
{{ RANKS[(mmRankUpdate && mmRankUpdate.rankNew) ?? 0] }}
</q-tooltip>
</q-img>
</template>

<template #score="{ score }: DemoResponse">
<span
:class="score[0] < score[1] ? 'text-red' : score[0] === score[1] ? 'text-blue-500' : 'text-green-500'"
class="font-semibold"
>
{{ score[0] }} - {{ score[1] }}
</span>
</template>

<template #kdd="{ kills, deaths }: DemoResponse">
<span :class="kills - deaths < 0 ? 'text-red' : 'text-green-500'" class="font-semibold">
{{ kills - deaths }}
</span>
</template>

<template #adr="{ damage, roundsWithDamageInfo }: DemoResponse">
{{ Format.number(damage / roundsWithDamageInfo) }}
</template>
</DataTable>
</q-page>
</template>

<style scoped lang="scss"></style>
56 changes: 38 additions & 18 deletions src/newui/src/components/common/DataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@ import debounce from 'lodash/debounce';
import snakeCase from 'lodash/snakeCase';
import get from 'lodash/get';
import { useQuasar } from 'quasar';
import { onMounted, ref } from 'vue';
import { computed, onMounted, ref } from 'vue';
import { DataTableHeader, DataTablePagination, DataTableRequestDetails } from '@/types/dataTable';
import notification from 'src/utils/notification';
import { has } from 'lodash';
/* ====================== Data ====================== */
const props = defineProps({
columns: {
type: Array as () => DataTableHeader[],
required: true,
},
apiCall: {
type: Function as () => any,
required: true,
},
entityName: {
type: String,
required: true,
},
});
const props = withDefaults(
defineProps<{
columns: DataTableHeader[];
apiCall: (params: any) => any;
entityName: string;
rowsPerPage?: number | string;
addActionsSlot?: boolean;
}>(),
{
rowsPerPage: 20,
addActionsSlot: false,
}
);
const tableRef = ref();
const items = ref<any[]>([]);
const pagination = ref({
page: 1,
rowsPerPage: 20,
rowsPerPage: props.rowsPerPage,
sortBy: '',
descending: false,
} as DataTablePagination);
Expand All @@ -43,6 +43,26 @@ if (props.entityName && $q.localStorage.has(entityListSortKey)) {
pagination.value.sortBy = $q.localStorage.getItem(entityListSortKey) as string;
}
const headers = computed(() => {
let headers: DataTableHeader[] = props.columns.map((el) => {
if (!has(el, 'align')) {
el.align = 'center';
}
if (!has(el, 'field')) {
el.field = el.name;
}
return el;
});
if (props.addActionsSlot) {
headers = headers.concat([{ classes: 'hs-action', field: 'actions', label: '', name: 'actions', sortable: false }]);
}
return headers;
});
/* ====================== Methods ====================== */
const getData = debounce(async (tableProps: DataTableRequestDetails) => {
Expand Down Expand Up @@ -106,11 +126,11 @@ onMounted(async () => {
<q-table
ref="tableRef"
v-model:pagination="pagination"
:columns="columns"
:columns="headers"
:loading="isLoading"
:pagination="pagination"
:rows="items"
:rows-per-page-options="[10, 20, 30, 40, 50]"
:rows-per-page-options="[10, 20, 25, 30, 40, 50]"
binary-state-sort
class="mt-3"
color="primary"
Expand Down
25 changes: 13 additions & 12 deletions src/newui/src/components/filters/DemoTypeFilter.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue';
import { DEMO_TYPE_IMAGES, DEMO_TYPES } from 'src/constants/demos';
/* ====================== Data ====================== */
Expand All @@ -13,36 +14,36 @@ const demoTypes = ref([
label: 'All',
},
{
value: 'valve',
value: DEMO_TYPES.VALVE,
label: 'Valve',
image: 'images/demoTypes/valve.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.VALVE],
},
{
value: 'esea',
value: DEMO_TYPES.ESEA,
label: 'ESEA',
image: 'images/demoTypes/esea.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.ESEA],
},
{
value: 'faceit',
value: DEMO_TYPES.FACEIT,
label: 'FACEIT',
image: 'images/demoTypes/faceit.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.FACEIT],
},
{
value: 'cevo',
value: DEMO_TYPES.CEVO,
label: 'CEVO',
image: 'images/demoTypes/cevo.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.CEVO],
},
{
value: 'esportal',
value: DEMO_TYPES.ESPORTAL,
label: 'Esportal',
image: 'images/demoTypes/esportal.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.ESPORTAL],
class: 'bg-blue-500 rounded',
style: 'height: 20px',
},
{
value: 'custom',
value: DEMO_TYPES.CUSTOM,
label: 'Custom',
image: 'images/demoTypes/custom.png',
image: DEMO_TYPE_IMAGES[DEMO_TYPES.CUSTOM],
style: 'height: 20px',
},
]);
Expand Down
17 changes: 17 additions & 0 deletions src/newui/src/constants/demos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Dictionary } from 'types/common';

export const DEMO_TYPES = {
VALVE: 'valve',
ESEA: 'esea',
FACEIT: 'faceit',
CEVO: 'cevo',
ESPORTAL: 'esportal',
CUSTOM: 'custom',
};

export const DEMO_TYPE_IMAGES: Dictionary = {};
DEMO_TYPE_IMAGES[DEMO_TYPES.VALVE] = 'images/demoTypes/valve.png';
DEMO_TYPE_IMAGES[DEMO_TYPES.ESEA] = 'images/demoTypes/esea.png';
DEMO_TYPE_IMAGES[DEMO_TYPES.FACEIT] = 'images/demoTypes/faceit.png';
DEMO_TYPE_IMAGES[DEMO_TYPES.ESPORTAL] = 'images/demoTypes/esportal.png';
DEMO_TYPE_IMAGES[DEMO_TYPES.CUSTOM] = 'images/demoTypes/custom.png';
1 change: 1 addition & 0 deletions src/newui/src/constants/ranks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const RANKS = {
0: 'Unknown',
1: 'Silver I',
2: 'Silver II',
3: 'Silver III',
Expand Down
10 changes: 5 additions & 5 deletions src/newui/src/pages/Player/Details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ provide('steamId', route.params.id);
/>
</div>

<q-splitter v-model="splitterModel" class="py-6" disable style="min-width: 80%">
<q-splitter v-model="splitterModel" class="py-6 min-w-full" disable>
<template #before>
<q-tabs v-model="tab" class="text-primary" vertical>
<q-tab name="demos" icon="mdi-history" label="Demos" />
Expand All @@ -260,19 +260,19 @@ provide('steamId', route.params.id);
vertical
>
<q-tab-panel name="demos">
<PlayerDemos />
<PlayerDemos :steamId="steamId" />
</q-tab-panel>

<q-tab-panel name="weapon-stats">
<PlayerWeaponStats />
<PlayerWeaponStats :steamId="steamId" />
</q-tab-panel>

<q-tab-panel name="banned-players">
<PlayerBanned />
<PlayerBanned :steamId="steamId" />
</q-tab-panel>

<q-tab-panel name="charts">
<PlayerCharts />
<PlayerCharts :steamId="steamId" />
</q-tab-panel>
</q-tab-panels>
</template>
Expand Down
10 changes: 5 additions & 5 deletions src/newui/src/pages/Player/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ import FolderFilter from 'src/components/filters/FolderFilter.vue';
const tableRef = ref();
const columns = [
{ label: 'Name', name: 'steamInfo', field: 'steamInfo', align: 'left', style: 'width: 35%' },
{ label: 'MM Rank', name: 'lastRank', field: 'lastRank', align: 'center', sortable: true },
{ label: 'Demos', name: 'demos', field: 'demos', align: 'center', sortable: true },
{ label: 'Last Played', name: 'lastTimestamp', field: 'lastTimestamp', align: 'center', sortable: true },
{ label: 'Name', name: 'steamInfo', align: 'left', style: 'width: 35%' },
{ label: 'MM Rank', name: 'lastRank', sortable: true },
{ label: 'Demos', name: 'demos', sortable: true },
{ label: 'Last Played', name: 'lastTimestamp', sortable: true },
] as DataTableHeader[];
const selectedFolder = ref('All');
/* ====================== Methods ====================== */
const getPlayers = async ({ limit, offset, orderBy }: ApiRequestParams) => {
const { playerCount, players } = await PlayerApi.get({
const { playerCount, players } = await PlayerApi.list({
...{ limit, offset, orderBy },
...(selectedFolder.value !== 'All' ? { folder: selectedFolder.value } : {}),
});
Expand Down
2 changes: 1 addition & 1 deletion src/newui/src/types/dataTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type DataTableHeader = {
/**
* Row Object property to determine value for this column or function which maps to the required property
*/
field: string | CallableFunction;
field?: string | CallableFunction;

/**
* If we use visible-columns, this col will always be visible
Expand Down
Loading

0 comments on commit d3a7b10

Please sign in to comment.