chore: added sorting icons to vehicles table

This commit is contained in:
2025-11-26 14:40:52 +01:00
parent c2c95d50f7
commit 8b42d2c395
3 changed files with 119 additions and 21 deletions
@@ -1,22 +1,40 @@
<template>
<div class="table-search-box">
<input type="text" placeholder="Wyszukaj pojazd..." v-model="vehicleSearchInput" />
<button @click="addVehicleRow()">DODAJ NOWY POJAZD</button>
<button class="btn--center" @click="clearSearchInput()">
<LucideX :size="18" :stroke-width="4" />
</button>
<button class="btn--center" @click="addVehicleRow()">
<LucidePlus :size="18" />
&nbsp;NOWY POJAZD
</button>
</div>
<div class="table-visible-results-box">
Pokazuj maks.
<input type="number" min="1" v-model="maxVisibleResults" />
wyników
</div>
<div class="table-wrapper">
<table class="vehicle-manager-table">
<thead>
<tr>
<td style="width: 50px">#</td>
<td style="width: 200px">Nazwa</td>
<td style="width: 150px">Typ</td>
<td style="width: 150px">Kabina (lok.)</td>
<td style="width: 170px">Grupa</td>
<td style="width: 100px">Tylko sponsorzy do</td>
<td style="width: 100px">Tylko zespół</td>
<td style="width: 50px">Ukryty</td>
<td style="width: 50px">Usuń</td>
<td
v-for="header in headers"
:style="`width: ${header.elementWidth}px`"
@click="sortTableBy(header.id)"
:data-sortable="header.sortable"
>
<div>
{{ header.title }}
<LucideArrowUp :size="18" v-if="activeSortKey === header.id && activeSortDir == 1" />
<LucideArrowDown :size="18" v-else-if="activeSortKey === header.id" />
</div>
</td>
</tr>
</thead>
@@ -76,7 +94,9 @@
{{ row.vehicleRef.hidden ? '' : '' }}
</td>
<td class="editable" @click="removeVehicle(row.vehicleRef.id)"><img src="/icon-trash.svg" alt="remove" /></td>
<td class="editable" @click="removeVehicleRow(row.vehicleRef.id)">
<img src="/icon-trash.svg" alt="remove" />
</td>
</tr>
</tbody>
</table>
@@ -86,21 +106,71 @@
<script lang="ts" setup>
import { computed, nextTick, ref, useTemplateRef } from 'vue';
import { useVehiclesStore } from '../../stores/vehicles.store';
import { IVehicleTableRow, VehicleEditRestrictionKey, VehicleEditRowKey } from '../../types/vehicles.types';
import { IVehicle, IVehicleTableRow, VehicleEditRestrictionKey, VehicleEditRowKey } from '../../types/vehicles.types';
import { LucideArrowDown, LucideArrowUp, LucidePlus, LucideX } from 'lucide-vue-next';
interface TableHeader {
id: string;
elementWidth: number;
title: string;
sortable: boolean;
}
const sorterFunctions: Record<string, (v1: IVehicle, v2: IVehicle) => number> = {
id: (v1, v2) => (v1.id - v2.id) * activeSortDir.value,
name: (v1, v2) => v1.name.localeCompare(v2.name) * activeSortDir.value,
cabinName: (v1, v2) => (v1.cabinName || '').localeCompare(v2.cabinName || '') * activeSortDir.value,
type: (v1, v2) => v1.type.localeCompare(v2.type) * activeSortDir.value,
group: (v1, v2) => (v1.group.id - v2.group.id) * activeSortDir.value,
sponsorOnly: (v1, v2) =>
((v1.restrictions?.sponsorOnly || v1.id) - (v2.restrictions?.sponsorOnly || v2.id)) * activeSortDir.value,
teamOnly: (v1, v2) =>
((v1.restrictions?.teamOnly ? 1 : v1.id) - (v2.restrictions?.teamOnly ? 1 : v2.id)) * activeSortDir.value,
hidden: (v1, v2) => (Number(v1.hidden) || v1.id) - (Number(v2.hidden) || v2.id) * activeSortDir.value,
};
const headers: TableHeader[] = [
{ id: 'id', elementWidth: 50, title: '#', sortable: true },
{ id: 'name', elementWidth: 200, title: 'Nazwa', sortable: true },
{ id: 'type', elementWidth: 150, title: 'Typ', sortable: true },
{ id: 'cabinName', elementWidth: 150, title: 'Kabina (lok.)', sortable: true },
{ id: 'group', elementWidth: 170, title: 'Grupa', sortable: true },
{ id: 'sponsorOnly', elementWidth: 130, title: 'Tylko sponsorzy do', sortable: true },
{ id: 'teamOnly', elementWidth: 100, title: 'Tylko zespół', sortable: true },
{ id: 'hidden', elementWidth: 75, title: 'Ukryty', sortable: true },
{ id: 'remove', elementWidth: 75, title: 'Usuń', sortable: false },
];
const vehiclesStore = useVehiclesStore();
const vehicleSearchInput = ref('');
const maxVisibleResults = ref(50);
const activeSortKey = ref<string>('id');
const activeSortDir = ref(1);
const currentEditingGroupId = ref(-1);
const selectGroup = useTemplateRef('select-group');
const vehiclesTableComp = computed(() => {
return vehiclesStore.vehiclesTable
.filter((row) => row.vehicleRef.name.toLowerCase().includes(vehicleSearchInput.value.trim().toLowerCase()))
.sort((r1, r2) => {
return r1.vehicleRef.id - r2.vehicleRef.id;
});
.sort((v1, v2) => sorterFunctions[activeSortKey.value](v1.vehicleRef, v2.vehicleRef))
.filter((_, i) => i < maxVisibleResults.value);
});
function clearSearchInput() {
vehicleSearchInput.value = '';
}
function sortTableBy(id: string) {
if (!(id in sorterFunctions)) return;
if (activeSortKey.value == id) activeSortDir.value *= -1;
else activeSortDir.value = 1;
activeSortKey.value = id;
}
async function editRowPrimitive(row: IVehicleTableRow, editKey: VehicleEditRowKey) {
if (!(editKey in row.vehicleRef)) return;
@@ -175,7 +245,6 @@ async function selectRowVehicleGroup(row: IVehicleTableRow) {
async function editVehicleGroup(e: Event, row: IVehicleTableRow) {
const id = (e.target as HTMLSelectElement).value;
if (row.vehicleRef.group.id !== +id) {
const updatedData = await vehiclesStore.updateVehicle(row.vehicleRef.id, 'vehicleGroupId', +id);
@@ -210,7 +279,7 @@ async function addVehicleRow() {
}
}
async function removeVehicle(id: number) {
async function removeVehicleRow(id: number) {
const confirmRemove = confirm('Czy na pewno chcesz usunąć ten pojazd?');
if (!confirmRemove) return;
@@ -222,5 +291,3 @@ async function removeVehicle(id: number) {
}
}
</script>
<style></style>