Skip to content

Commit c4cfd43

Browse files
authored
Merge pull request #20 from ComputerScienceHouse/table-sorting
Add Table Sorting By Column
1 parent faae53f commit c4cfd43

File tree

4 files changed

+104
-14
lines changed

4 files changed

+104
-14
lines changed

src/frontend/src/components/CarRow.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,8 @@ tr:hover > * {
5151
.rotated {
5252
transform: rotate(90deg);
5353
}
54+
55+
tr {
56+
cursor: pointer;
57+
}
5458
</style>

src/frontend/src/components/CarTable.vue

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
import CarRowGroup from './CarRowGroup.vue';
33
import LeaveCarModal from './LeaveCarModal.vue';
44
import Loading from './LoadingWheel.vue';
5-
6-
const eventStore = useEventStore();
5+
import CaretUp from './icons/CaretUp.vue';
6+
import CaretDown from './icons/CaretDown.vue';
7+
import BlankIcon from './icons/BlankIcon.vue';
78
</script>
89

910
<template>
@@ -12,23 +13,34 @@ const eventStore = useEventStore();
1213
<table class="table">
1314
<thead>
1415
<tr>
15-
<th scope="col">Driver</th>
16-
<th scope="col">Capacity</th>
17-
<th scope="col">Departure</th>
18-
<th scope="col">Return</th>
16+
<th scope="col" @click="changeSort('driver')">
17+
Driver <CaretUp v-if="sortingOrder.fieldName == 'driver' && sortingOrder.asc" />
18+
<CaretDown v-if="sortingOrder.fieldName == 'driver' && !sortingOrder.asc" />
19+
<BlankIcon v-if="sortingOrder.fieldName != 'driver'" />
20+
</th>
21+
<th scope="col" @click="changeSort('capacity')">
22+
Capacity <CaretUp v-if="sortingOrder.fieldName == 'capacity' && sortingOrder.asc" />
23+
<CaretDown v-if="sortingOrder.fieldName == 'capacity' && !sortingOrder.asc" />
24+
<BlankIcon v-if="sortingOrder.fieldName != 'capacity'" />
25+
</th>
26+
<th scope="col" @click="changeSort('departure')">
27+
Departure <CaretUp v-if="sortingOrder.fieldName == 'departure' && sortingOrder.asc" />
28+
<CaretDown v-if="sortingOrder.fieldName == 'departure' && !sortingOrder.asc" />
29+
<BlankIcon v-if="sortingOrder.fieldName != 'departure'" />
30+
</th>
31+
<th scope="col" @click="changeSort('return')">
32+
Return <CaretUp v-if="sortingOrder.fieldName == 'return' && sortingOrder.asc" />
33+
<CaretDown v-if="sortingOrder.fieldName == 'return' && !sortingOrder.asc" />
34+
<BlankIcon v-if="sortingOrder.fieldName != 'return'" />
35+
</th>
1936
<th scope="col"></th>
2037
</tr>
2138
</thead>
2239
<tbody>
23-
<CarRowGroup
24-
v-for="car in eventStore.selectedEventCars"
25-
:car="car"
26-
:eventId="eventId"
27-
:key="car.id"
28-
/>
40+
<CarRowGroup v-for="car in sortedCars" :car="car" :eventId="eventId" :key="car.id" />
2941
</tbody>
3042
</table>
31-
<LeaveCarModal v-for="car in eventStore.selectedEventCars" :carId="car!.id" :key="car!.id" />
43+
<LeaveCarModal v-for="car in sortedCars" :carId="car!.id" :key="car!.id" />
3244
</div>
3345
</template>
3446

@@ -38,13 +50,22 @@ import { defineComponent } from 'vue';
3850
import { useEventStore } from '@/stores/events';
3951
import { usePopupStore } from '@/stores/popup';
4052
53+
interface SortingOrder {
54+
fieldName: string;
55+
asc: boolean;
56+
}
57+
4158
export default defineComponent({
4259
props: {
4360
eventId: Number
4461
},
4562
data() {
4663
return {
47-
loading: true
64+
loading: true,
65+
sortingOrder: {
66+
fieldName: 'driver',
67+
asc: true
68+
} as SortingOrder
4869
};
4970
},
5071
methods: {
@@ -67,10 +88,47 @@ export default defineComponent({
6788
const popupStore = usePopupStore();
6889
popupStore.addPopup(PopupType.Danger, 'Failed to Get Cars. An unknown error occured.');
6990
}
91+
},
92+
changeSort(field: string) {
93+
if (this.sortingOrder.fieldName === field) {
94+
this.sortingOrder.asc = !this.sortingOrder.asc;
95+
} else {
96+
this.sortingOrder.fieldName = field;
97+
this.sortingOrder.asc = true;
98+
}
7099
}
71100
},
72101
created() {
73102
this.fetchCarData(); // Fetch card data when the component is created
103+
},
104+
computed: {
105+
sortedCars() {
106+
const eventStore = useEventStore();
107+
const { fieldName, asc } = this.sortingOrder;
108+
return [...(eventStore.selectedEventCars || [])].sort((a, b) => {
109+
const compare = (valA: string | number, valB: string | number) => {
110+
if (valA < valB) return asc ? -1 : 1;
111+
if (valA > valB) return asc ? 1 : -1;
112+
return 0;
113+
};
114+
115+
switch (fieldName) {
116+
case 'driver':
117+
return compare(a.driver.name, b.driver.name);
118+
case 'capacity':
119+
return compare(a.riders.length, b.riders.length);
120+
case 'departure':
121+
return compare(
122+
new Date(a.departureTime).getTime(),
123+
new Date(b.departureTime).getTime()
124+
);
125+
case 'return':
126+
return compare(new Date(a.returnTime).getTime(), new Date(b.returnTime).getTime());
127+
default:
128+
return 0;
129+
}
130+
});
131+
}
74132
}
75133
});
76134
</script>
@@ -97,4 +155,8 @@ export default defineComponent({
97155
opacity: 0;
98156
transform: translateY(-30px);
99157
}
158+
159+
th {
160+
cursor: pointer;
161+
}
100162
</style>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
width="16"
5+
height="16"
6+
fill="currentColor"
7+
class="bi bi-blank"
8+
viewBox="0 0 16 16"
9+
></svg>
10+
</template>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
width="16"
5+
height="16"
6+
fill="currentColor"
7+
class="bi bi-caret-up-fill"
8+
viewBox="0 0 16 16"
9+
>
10+
<path
11+
d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"
12+
/>
13+
</svg>
14+
</template>

0 commit comments

Comments
 (0)