Files
backend/resources/js/Pages/Supervisor/Pricing/Index.vue
T
2026-06-28 12:29:53 +02:00

243 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import SupervisorLayout from '@/Layouts/SupervisorLayout.vue';
import { Head, useForm } from '@inertiajs/vue3';
import { ref } from 'vue';
const props = defineProps({
rules: {
type: Array,
default: () => [],
},
establishments: {
type: Array,
default: () => [],
},
machineTypes: {
type: Object,
default: () => ({}),
},
dayTypes: {
type: Object,
default: () => ({}),
},
});
const editingId = ref(null);
const showForm = ref(false);
const emptyForm = () => ({
establishment_id: props.establishments[0]?.id ?? '',
machine_id: null,
machine_type: '',
day_type: 'all',
slot_start: '08:00',
slot_end: '22:00',
price: '',
label: '',
requires_app: false,
priority: 100,
is_active: true,
});
const form = useForm(emptyForm());
const startCreate = () => {
editingId.value = null;
form.defaults(emptyForm());
form.reset();
showForm.value = true;
};
const startEdit = (rule) => {
editingId.value = rule.id;
form.defaults({
establishment_id: rule.establishment_id,
machine_id: rule.machine_id,
machine_type: rule.machine_type ?? '',
day_type: rule.day_type,
slot_start: rule.slot_start,
slot_end: rule.slot_end,
price: rule.price,
label: rule.label ?? '',
requires_app: rule.requires_app,
priority: rule.priority,
is_active: rule.is_active,
});
form.reset();
showForm.value = true;
};
const cancelForm = () => {
showForm.value = false;
editingId.value = null;
form.reset();
};
const submit = () => {
const payload = {
...form.data(),
machine_id: form.machine_id || null,
machine_type: form.machine_type || null,
};
if (editingId.value) {
form.transform(() => payload).put(route('supervisor.pricing.update', editingId.value), {
onSuccess: cancelForm,
});
} else {
form.transform(() => payload).post(route('supervisor.pricing.store'), {
onSuccess: cancelForm,
});
}
};
const destroy = (id) => {
if (confirm('Supprimer cette règle tarifaire ?')) {
useForm({}).delete(route('supervisor.pricing.destroy', id));
}
};
const formatCurrency = (value) =>
new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(value ?? 0);
</script>
<template>
<Head title="Tarifs" />
<SupervisorLayout title="Tarifs">
<div class="mb-4 flex justify-end">
<PrimaryButton v-if="!showForm" @click="startCreate">
Nouvelle règle
</PrimaryButton>
</div>
<!-- Inline form -->
<div v-if="showForm" class="mb-6 rounded-lg border border-indigo-200 bg-white p-6 shadow">
<h2 class="mb-4 text-lg font-semibold text-gray-800">
{{ editingId ? 'Modifier la règle' : 'Nouvelle règle tarifaire' }}
</h2>
<form @submit.prevent="submit" class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div>
<label class="block text-xs font-medium text-gray-500">Établissement</label>
<select
v-model="form.establishment_id"
required
class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm"
>
<option v-for="est in establishments" :key="est.id" :value="est.id">
{{ est.name }}
</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Type de machine</label>
<select v-model="form.machine_type" class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm">
<option value="">Tous types</option>
<option v-for="(label, value) in machineTypes" :key="value" :value="value">
{{ label }}
</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Jour</label>
<select v-model="form.day_type" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm">
<option v-for="(label, value) in dayTypes" :key="value" :value="value">
{{ label }}
</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Début créneau</label>
<input v-model="form.slot_start" type="time" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Fin créneau</label>
<input v-model="form.slot_end" type="time" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Prix ()</label>
<input v-model="form.price" type="number" step="0.01" min="0" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Libellé</label>
<input v-model="form.label" type="text" class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
</div>
<div>
<label class="block text-xs font-medium text-gray-500">Priorité</label>
<input v-model="form.priority" type="number" min="0" class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
</div>
<div class="flex items-end gap-4">
<label class="flex items-center gap-2 text-sm">
<input v-model="form.requires_app" type="checkbox" class="rounded border-gray-300 text-indigo-600" />
App requise
</label>
<label class="flex items-center gap-2 text-sm">
<input v-model="form.is_active" type="checkbox" class="rounded border-gray-300 text-indigo-600" />
Active
</label>
</div>
<div class="flex gap-2 sm:col-span-2 lg:col-span-3">
<PrimaryButton type="submit" :disabled="form.processing">
{{ editingId ? 'Enregistrer' : 'Créer' }}
</PrimaryButton>
<SecondaryButton type="button" @click="cancelForm">Annuler</SecondaryButton>
</div>
</form>
</div>
<!-- Rules list -->
<div class="overflow-hidden rounded-lg bg-white shadow">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Établissement</th>
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Créneau</th>
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Prix</th>
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Statut</th>
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<tr v-if="rules.length === 0">
<td colspan="6" class="px-4 py-8 text-center text-sm text-gray-500">
Aucune règle tarifaire configurée.
</td>
</tr>
<tr v-for="rule in rules" :key="rule.id" class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm text-gray-800">{{ rule.establishment_name }}</td>
<td class="px-4 py-3 text-sm text-gray-600">
{{ rule.slot_start }} {{ rule.slot_end }}
<span class="text-xs text-gray-400">({{ rule.day_type_label }})</span>
</td>
<td class="px-4 py-3 text-sm text-gray-600">
{{ rule.machine_type_label ?? 'Tous' }}
</td>
<td class="px-4 py-3 text-sm font-medium text-gray-800">
{{ formatCurrency(rule.price) }}
</td>
<td class="px-4 py-3">
<span
class="rounded-full px-2.5 py-0.5 text-xs font-medium"
:class="rule.is_active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-600'"
>
{{ rule.is_active ? 'Active' : 'Inactive' }}
</span>
</td>
<td class="px-4 py-3 text-right text-sm">
<button @click="startEdit(rule)" class="text-indigo-600 hover:text-indigo-800">
Modifier
</button>
<button @click="destroy(rule.id)" class="ms-3 text-red-600 hover:text-red-800">
Supprimer
</button>
</td>
</tr>
</tbody>
</table>
</div>
</SupervisorLayout>
</template>