feat: multi-tenant SaaS implementation - admin interface, tenant isolation, and UI updates
This commit is contained in:
105
resources/js/Pages/Admin/Tenants/Index.vue
Normal file
105
resources/js/Pages/Admin/Tenants/Index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<script setup>
|
||||
import { Head, useForm, Link } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import AdminLayout from '@/Layouts/AdminLayout.vue';
|
||||
|
||||
const props = defineProps({
|
||||
tenants: Array
|
||||
});
|
||||
|
||||
const isCreating = ref(false);
|
||||
const editingTenant = ref(null);
|
||||
|
||||
const form = useForm({
|
||||
name: ''
|
||||
});
|
||||
|
||||
const submit = () => {
|
||||
if (editingTenant.value) {
|
||||
form.put(route('admin.tenants.update', editingTenant.value.id), {
|
||||
onSuccess: () => {
|
||||
editingTenant.value = null;
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
form.post(route('admin.tenants.store'), {
|
||||
onSuccess: () => {
|
||||
isCreating.value = false;
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const editTenant = (tenant) => {
|
||||
editingTenant.value = tenant;
|
||||
form.name = tenant.name;
|
||||
isCreating.value = true;
|
||||
};
|
||||
|
||||
const deleteTenant = (tenant) => {
|
||||
if (confirm('Êtes-vous sûr de vouloir supprimer cette structure ?')) {
|
||||
form.delete(route('admin.tenants.destroy', tenant.id));
|
||||
}
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
isCreating.value = false;
|
||||
editingTenant.value = null;
|
||||
form.reset();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Gestion des Structures" />
|
||||
<AdminLayout>
|
||||
<template #header>Gestion des Structures (SaaS)</template>
|
||||
|
||||
<div class="mb-6 flex justify-between items-center">
|
||||
<h1 class="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-indigo-500 to-purple-500">
|
||||
Structures / Tenants
|
||||
</h1>
|
||||
<button v-if="!isCreating" @click="isCreating = true" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
|
||||
Ajouter une Structure
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="isCreating" class="mb-8 p-6 bg-white dark:bg-slate-800 rounded-xl shadow border border-slate-200 dark:border-slate-700">
|
||||
<h2 class="text-lg font-bold mb-4">{{ editingTenant ? 'Modifier la structure' : 'Nouvelle structure' }}</h2>
|
||||
<form @submit.prevent="submit" class="flex items-center gap-4">
|
||||
<input v-model="form.name" type="text" placeholder="Nom du service ou client" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" required />
|
||||
<button type="submit" class="px-4 py-2 bg-indigo-600 focus:bg-indigo-700 text-white rounded-lg whitespace-nowrap" :disabled="form.processing">
|
||||
{{ editingTenant ? 'Mettre à jour' : 'Créer' }}
|
||||
</button>
|
||||
<button type="button" @click="cancel" class="px-4 py-2 bg-slate-200 text-slate-800 rounded-lg whitespace-nowrap">Annuler</button>
|
||||
</form>
|
||||
<div v-if="form.errors.name" class="mt-2 text-sm text-red-600">{{ form.errors.name }}</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-slate-800 rounded-xl shadow overflow-hidden border border-slate-200 dark:border-slate-700">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-slate-50 dark:bg-slate-700/50 border-b border-slate-200 dark:border-slate-700">
|
||||
<th class="py-4 px-6 font-semibold text-slate-600 dark:text-slate-300">ID</th>
|
||||
<th class="py-4 px-6 font-semibold text-slate-600 dark:text-slate-300">Nom de la structure</th>
|
||||
<th class="py-4 px-6 font-semibold text-slate-600 dark:text-slate-300 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="tenant in tenants" :key="tenant.id" class="border-b border-slate-100 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-700/50 transition-colors">
|
||||
<td class="py-3 px-6 text-slate-500">{{ tenant.id }}</td>
|
||||
<td class="py-3 px-6 font-medium">{{ tenant.name }}</td>
|
||||
<td class="py-3 px-6 text-right space-x-2">
|
||||
<button @click="editTenant(tenant)" class="text-indigo-600 hover:text-indigo-900 px-3 py-1 rounded bg-indigo-50 hover:bg-indigo-100 transition-colors">Modifier</button>
|
||||
<button @click="deleteTenant(tenant)" class="text-red-600 hover:text-red-900 px-3 py-1 rounded bg-red-50 hover:bg-red-100 transition-colors">Supprimer</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="tenants.length === 0">
|
||||
<td colspan="3" class="py-8 text-center text-slate-500">Aucune structure. Ajoutez-en une pour commencer.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user