initial commit
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
<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({
|
||||
promotions: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
establishments: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
machineTypes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
discountTypes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const editingId = ref(null);
|
||||
const showForm = ref(false);
|
||||
|
||||
const emptyForm = () => ({
|
||||
establishment_id: props.establishments[0]?.id ?? '',
|
||||
machine_type: 'all',
|
||||
discount_type: 'percent',
|
||||
discount_value: '',
|
||||
starts_at: '',
|
||||
ends_at: '',
|
||||
description: '',
|
||||
is_active: true,
|
||||
});
|
||||
|
||||
const form = useForm(emptyForm());
|
||||
|
||||
const startCreate = () => {
|
||||
editingId.value = null;
|
||||
form.defaults(emptyForm());
|
||||
form.reset();
|
||||
showForm.value = true;
|
||||
};
|
||||
|
||||
const startEdit = (promotion) => {
|
||||
editingId.value = promotion.id;
|
||||
form.defaults({
|
||||
establishment_id: promotion.establishment_id,
|
||||
machine_type: promotion.machine_type,
|
||||
discount_type: promotion.discount_type,
|
||||
discount_value: promotion.discount_value,
|
||||
starts_at: promotion.starts_at,
|
||||
ends_at: promotion.ends_at,
|
||||
description: promotion.description ?? '',
|
||||
is_active: promotion.is_active,
|
||||
});
|
||||
form.reset();
|
||||
showForm.value = true;
|
||||
};
|
||||
|
||||
const cancelForm = () => {
|
||||
showForm.value = false;
|
||||
editingId.value = null;
|
||||
form.reset();
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
if (editingId.value) {
|
||||
form.put(route('supervisor.promotions.update', editingId.value), {
|
||||
onSuccess: cancelForm,
|
||||
});
|
||||
} else {
|
||||
form.post(route('supervisor.promotions.store'), {
|
||||
onSuccess: cancelForm,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const destroy = (id) => {
|
||||
if (confirm('Supprimer cette promotion ?')) {
|
||||
useForm({}).delete(route('supervisor.promotions.destroy', id));
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (iso) => {
|
||||
if (!iso) return '—';
|
||||
return new Intl.DateTimeFormat('fr-FR', {
|
||||
dateStyle: 'short',
|
||||
timeStyle: 'short',
|
||||
}).format(new Date(iso));
|
||||
};
|
||||
|
||||
const formatDiscount = (promotion) => {
|
||||
if (promotion.discount_type === 'percent') {
|
||||
return `-${promotion.discount_value} %`;
|
||||
}
|
||||
return `-${new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(promotion.discount_value)}`;
|
||||
};
|
||||
|
||||
const isCurrentlyActive = (promotion) => {
|
||||
const now = new Date();
|
||||
return (
|
||||
promotion.is_active &&
|
||||
new Date(promotion.starts_at) <= now &&
|
||||
new Date(promotion.ends_at) >= now
|
||||
);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Promotions" />
|
||||
|
||||
<SupervisorLayout title="Promotions">
|
||||
<div class="mb-4 flex justify-end">
|
||||
<PrimaryButton v-if="!showForm" @click="startCreate">
|
||||
Nouvelle promotion
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
|
||||
<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 promotion' : 'Nouvelle promotion' }}
|
||||
</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" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm">
|
||||
<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">Type de remise</label>
|
||||
<select v-model="form.discount_type" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm">
|
||||
<option v-for="(label, value) in discountTypes" :key="value" :value="value">
|
||||
{{ label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-500">Valeur</label>
|
||||
<input v-model="form.discount_value" 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">Début</label>
|
||||
<input v-model="form.starts_at" type="datetime-local" 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</label>
|
||||
<input v-model="form.ends_at" type="datetime-local" required class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
|
||||
</div>
|
||||
<div class="sm:col-span-2 lg:col-span-3">
|
||||
<label class="block text-xs font-medium text-gray-500">Description</label>
|
||||
<textarea v-model="form.description" rows="2" class="mt-1 block w-full rounded-md border-gray-300 text-sm shadow-sm" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<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>
|
||||
|
||||
<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">Remise</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Période</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Machines</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="promotions.length === 0">
|
||||
<td colspan="6" class="px-4 py-8 text-center text-sm text-gray-500">
|
||||
Aucune promotion configurée.
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="promotion in promotions" :key="promotion.id" class="hover:bg-gray-50">
|
||||
<td class="px-4 py-3 text-sm text-gray-800">{{ promotion.establishment_name }}</td>
|
||||
<td class="px-4 py-3 text-sm font-medium text-green-700">
|
||||
{{ formatDiscount(promotion) }}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-gray-600">
|
||||
<div>{{ formatDate(promotion.starts_at) }}</div>
|
||||
<div class="text-xs text-gray-400">→ {{ formatDate(promotion.ends_at) }}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-gray-600">{{ promotion.machine_type_label }}</td>
|
||||
<td class="px-4 py-3">
|
||||
<span
|
||||
class="rounded-full px-2.5 py-0.5 text-xs font-medium"
|
||||
:class="
|
||||
isCurrentlyActive(promotion)
|
||||
? 'bg-green-100 text-green-800'
|
||||
: promotion.is_active
|
||||
? 'bg-yellow-100 text-yellow-800'
|
||||
: 'bg-gray-100 text-gray-600'
|
||||
"
|
||||
>
|
||||
{{
|
||||
isCurrentlyActive(promotion)
|
||||
? 'En cours'
|
||||
: promotion.is_active
|
||||
? 'Programmée'
|
||||
: 'Inactive'
|
||||
}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right text-sm">
|
||||
<button @click="startEdit(promotion)" class="text-indigo-600 hover:text-indigo-800">
|
||||
Modifier
|
||||
</button>
|
||||
<button @click="destroy(promotion.id)" class="ms-3 text-red-600 hover:text-red-800">
|
||||
Supprimer
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</SupervisorLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user