Skip to content

Commit b316d37

Browse files
committed
feature: create Table component and integrate it into all the pages that required it
1 parent e211754 commit b316d37

File tree

9 files changed

+314
-20
lines changed

9 files changed

+314
-20
lines changed

app/Http/Controllers/DeliveryNoteController.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace App\Http\Controllers;
44

55
use Illuminate\Http\Request;
6+
use App\Models\DeliveryNote;
7+
use Inertia\Inertia;
68

79
class DeliveryNoteController extends Controller
810
{
@@ -11,7 +13,10 @@ class DeliveryNoteController extends Controller
1113
*/
1214
public function index()
1315
{
14-
//
16+
$deliveryNotes = DeliveryNote::all();
17+
return Inertia::render('DeliveryNotes/Show', [
18+
'delivery_notes' => $deliveryNotes
19+
]);
1520
}
1621

1722
/**

resources/js/Components/DataTable.vue

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<script setup>
2+
import { computed, ref, watch } from 'vue';
3+
4+
const props = defineProps({
5+
data: {
6+
type: Array,
7+
required: true
8+
},
9+
columns: {
10+
type: Array,
11+
required: true
12+
},
13+
itemsPerPage: {
14+
type: Number,
15+
default: 10
16+
}
17+
});
18+
19+
const currentPage = ref(1);
20+
21+
const totalItems = computed(() => props.data.length);
22+
const totalPages = computed(() => Math.ceil(totalItems.value / props.itemsPerPage));
23+
24+
const startIndex = computed(() => (currentPage.value - 1) * props.itemsPerPage);
25+
const endIndex = computed(() => Math.min(startIndex.value + props.itemsPerPage, totalItems.value));
26+
27+
const paginatedData = computed(() => {
28+
return props.data.slice(startIndex.value, endIndex.value);
29+
});
30+
31+
const displayedPages = computed(() => {
32+
const delta = 2;
33+
const range = [];
34+
const rangeWithDots = [];
35+
let l;
36+
37+
for (let i = 1; i <= totalPages.value; i++) {
38+
if (i === 1 || i === totalPages.value ||
39+
(i >= currentPage.value - delta && i <= currentPage.value + delta)) {
40+
range.push(i);
41+
}
42+
}
43+
44+
range.forEach(i => {
45+
if (l) {
46+
if (i - l === 2) {
47+
rangeWithDots.push(l + 1);
48+
} else if (i - l !== 1) {
49+
rangeWithDots.push('...');
50+
}
51+
}
52+
rangeWithDots.push(i);
53+
l = i;
54+
});
55+
56+
return rangeWithDots;
57+
});
58+
59+
const previousPage = () => {
60+
if (currentPage.value > 1) {
61+
currentPage.value--;
62+
}
63+
};
64+
65+
const nextPage = () => {
66+
if (currentPage.value < totalPages.value) {
67+
currentPage.value++;
68+
}
69+
};
70+
71+
const goToPage = (page) => {
72+
if (typeof page === 'number') {
73+
currentPage.value = page;
74+
}
75+
};
76+
77+
watch(() => props.data, () => {
78+
currentPage.value = 1;
79+
});
80+
</script>
81+
82+
<template>
83+
<div class="overflow-x-auto bg-white rounded-lg shadow">
84+
<table class="min-w-full border-collapse rounded-lg overflow-hidden">
85+
<thead class="bg-red-500">
86+
<tr>
87+
<th v-for="(column, index) in columns"
88+
:key="column.key"
89+
class="px-6 py-3 text-left text-xs text-white font-medium text-gray-700 uppercase tracking-wider border-b border-gray-200">
90+
{{ column.label }}
91+
</th>
92+
</tr>
93+
</thead>
94+
<tbody class="bg-white">
95+
<tr v-for="item in paginatedData"
96+
:key="item.id"
97+
class="hover:bg-gray-50 border-b border-gray-200">
98+
<td v-for="column in columns"
99+
:key="column.key"
100+
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
101+
{{ item[column.key] }}
102+
</td>
103+
</tr>
104+
</tbody>
105+
</table>
106+
107+
<!-- Paginación -->
108+
<div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
109+
<div class="flex-1 flex justify-between sm:hidden">
110+
<button @click="previousPage"
111+
:disabled="currentPage === 1"
112+
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
113+
:class="{ 'opacity-50 cursor-not-allowed': currentPage === 1 }">
114+
Anterior
115+
</button>
116+
<button @click="nextPage"
117+
:disabled="currentPage >= totalPages"
118+
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
119+
:class="{ 'opacity-50 cursor-not-allowed': currentPage >= totalPages }">
120+
Siguiente
121+
</button>
122+
</div>
123+
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
124+
<div>
125+
<p class="text-sm text-gray-700">
126+
Mostrando
127+
<span class="font-medium">{{ startIndex + 1 }}</span>
128+
a
129+
<span class="font-medium">{{ endIndex }}</span>
130+
de
131+
<span class="font-medium">{{ totalItems }}</span>
132+
resultados
133+
</p>
134+
</div>
135+
<div>
136+
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
137+
<button @click="previousPage"
138+
:disabled="currentPage === 1"
139+
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
140+
:class="{ 'opacity-50 cursor-not-allowed': currentPage === 1 }">
141+
<span class="sr-only">Anterior</span>
142+
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
143+
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
144+
</svg>
145+
</button>
146+
<button v-for="page in displayedPages"
147+
:key="page"
148+
@click="goToPage(page)"
149+
:class="[
150+
currentPage === page
151+
? 'z-10 bg-gray-50 border-gray-300 text-gray-600'
152+
: 'bg-white border-gray-300 text-gray-500 hover:bg-gray-50',
153+
'relative inline-flex items-center px-4 py-2 border text-sm font-medium'
154+
]">
155+
{{ page }}
156+
</button>
157+
<button @click="nextPage"
158+
:disabled="currentPage >= totalPages"
159+
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
160+
:class="{ 'opacity-50 cursor-not-allowed': currentPage >= totalPages }">
161+
<span class="sr-only">Siguiente</span>
162+
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
163+
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
164+
</svg>
165+
</button>
166+
</nav>
167+
</div>
168+
</div>
169+
</div>
170+
</div>
171+
</template>

resources/js/Pages/Buys.vue

-6
This file was deleted.

resources/js/Pages/Clients.vue

+31-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,39 @@
11
<script setup>
2+
import { Head } from '@inertiajs/vue3';
3+
import DataTable from '@/Components/DataTable.vue';
4+
25
const props = defineProps({
3-
clients: Array
6+
clients: {
7+
type: Array,
8+
required: true
9+
}
410
});
11+
12+
const columns = [
13+
{ key: 'id', label: 'ID' },
14+
{ key: 'name', label: 'Nombre' },
15+
{ key: 'email', label: 'Email' },
16+
{ key: 'telephone', label: 'Teléfono' },
17+
{ key: 'city', label: 'Ciudad' },
18+
{ key: 'postal_code', label: 'Código Postal' },
19+
{ key: 'DNI', label: 'DNI' },
20+
{ key: 'registered_at', label: 'Fecha de Registro' },
21+
{ key: 'created_at', label: 'Fecha de Creación' }
22+
];
523
</script>
624

725
<template>
8-
<div class="clients" v-for="client in clients" :key="client.id">
9-
<span>name: {{ client.name }}, email: {{ client.email }}, vehicle count: {{ client.vehicle_count }}</span>
26+
<Head title="Clientes" />
27+
28+
<div class="container mx-auto py-8 px-4">
29+
<h1 class="text-2xl font-bold text-gray-800 mb-6">
30+
Clientes
31+
</h1>
32+
33+
<DataTable
34+
:data="clients"
35+
:columns="columns"
36+
:items-per-page="10"
37+
/>
1038
</div>
1139
</template>

resources/js/Pages/Dashboard/Show.vue

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const props = defineProps({
1010
const navigateToClients = () => router.get('/clients');
1111
const navigateToVehicles = () => router.get('/vehicles');
1212
const navigateToRepairs = () => router.get('/repairs');
13-
const navigateToBuys = () => router.get('/buys');
13+
const navigateToDeliveryNotes = () => router.get('/delivery-notes');
1414
</script>
1515

1616
<template>
@@ -41,17 +41,17 @@ const navigateToBuys = () => router.get('/buys');
4141
<Tile
4242
title="Compras"
4343
description="Gestión de compras"
44-
@click="navigateToBuys"
44+
@click="navigateToDeliveryNotes"
4545
/>
4646
<Tile
4747
title="Compras"
4848
description="Gestión de reparaciones"
49-
@click="navigateToBuys"
49+
@click="navigateToDeliveryNotes"
5050
/>
5151
<Tile
5252
title="Compras"
5353
description="Gestión de compras"
54-
@click="navigateToBuys"
54+
@click="navigateToDeliveryNotes"
5555
/>
5656
</div>
5757
</div>
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<script setup>
2+
import { Head } from '@inertiajs/vue3';
3+
import DataTable from '@/Components/DataTable.vue';
4+
5+
const props = defineProps({
6+
delivery_notes: {
7+
type: Array,
8+
required: true
9+
}
10+
});
11+
12+
const columns = [
13+
{ key: 'id', label: 'ID' },
14+
{ key: 'type', label: 'Tipo' },
15+
{ key: 'supplier', label: 'Proveedor' },
16+
{ key: 'family', label: 'Familia' },
17+
{ key: 'RRP', label: 'PVP' },
18+
{ key: 'cost', label: 'Coste' },
19+
{ key: 'margin', label: 'Margen' },
20+
{ key: 'profit', label: 'Beneficio' },
21+
{ key: 'added_at', label: 'Fecha de Alta' },
22+
{ key: 'created_at', label: 'Fecha de Creación' }
23+
];
24+
</script>
25+
26+
<template>
27+
<Head title="Albaranes" />
28+
29+
<div class="container mx-auto py-8 px-4">
30+
<h1 class="text-2xl font-bold text-gray-800 mb-6">
31+
Albaranes
32+
</h1>
33+
34+
<DataTable
35+
:data="delivery_notes"
36+
:columns="columns"
37+
:items-per-page="10"
38+
/>
39+
</div>
40+
</template>

resources/js/Pages/Repairs.vue

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
11
<script setup>
2+
import { Head } from '@inertiajs/vue3';
3+
import DataTable from '@/Components/DataTable.vue';
4+
25
const props = defineProps({
3-
repairs: Array
6+
repairs: {
7+
type: Array,
8+
required: true
9+
}
410
});
11+
12+
const columns = [
13+
{ key: 'id', label: 'ID' },
14+
{ key: 'repair_type_id', label: 'Tipo de Reparación' },
15+
{ key: 'vehicle_id', label: 'ID Vehículo' },
16+
{ key: 'observations', label: 'Observaciones' },
17+
{ key: 'status', label: 'Estado' },
18+
{ key: 'started_at', label: 'Fecha de Inicio' },
19+
{ key: 'created_at', label: 'Fecha de Creación' }
20+
];
521
</script>
622

723
<template>
8-
<div class="repairs" v-for="repair in repairs" :key="repair.id">
9-
<span>id: {{ repair.id }}, state: {{ repair.status }}</span>
24+
<Head title="Reparaciones" />
25+
26+
<div class="container mx-auto py-8 px-4">
27+
<h1 class="text-2xl font-bold text-gray-800 mb-6">
28+
Reparaciones
29+
</h1>
30+
31+
<DataTable
32+
:data="repairs"
33+
:columns="columns"
34+
:items-per-page="10"
35+
/>
1036
</div>
1137
</template>

0 commit comments

Comments
 (0)