feat: implementation du role Gestionnaire RH et refonte de la gestion des offres

This commit is contained in:
jeremy bayse
2026-05-09 11:21:40 +02:00
parent 97a8b9443d
commit 9edf79e8ba
23 changed files with 1223 additions and 232 deletions

View File

@@ -12,7 +12,7 @@ const props = defineProps({
const page = usePage();
const user = computed(() => page.props.auth.user);
const isAdmin = computed(() => ['admin', 'super_admin'].includes(user.value?.role));
const isAdmin = computed(() => ['admin', 'super_admin', 'gestionnaire_rh'].includes(user.value?.role));
const layout = computed(() => isAdmin.value ? AdminLayout : AuthenticatedLayout);
import axios from 'axios';
@@ -59,7 +59,7 @@ const triggerMassAssignmentHoneypot = async () => {
<div v-if="isAdmin" class="space-y-8 font-sans text-anthracite">
<!-- KPI Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6">
<div :class="['grid gap-6', user.role === 'gestionnaire_rh' ? 'grid-cols-1 max-w-sm mx-auto' : 'grid-cols-1 md:grid-cols-2 lg:grid-cols-5']">
<!-- Total Candidats -->
<div class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-primary/5 transition-all duration-300 relative overflow-hidden group">
<div class="text-[10px] font-subtitle font-black uppercase tracking-widest text-anthracite/40">Total Candidats</div>
@@ -68,7 +68,7 @@ const triggerMassAssignmentHoneypot = async () => {
</div>
<!-- Candidats Retenus -->
<div class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-highlight/20 transition-all duration-300 relative overflow-hidden group">
<div v-if="user.role !== 'gestionnaire_rh'" class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-highlight/20 transition-all duration-300 relative overflow-hidden group">
<div class="absolute inset-0 bg-gradient-to-br from-highlight/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div class="relative z-10">
<div class="text-highlight text-[10px] font-subtitle font-black uppercase tracking-widest flex items-center gap-1.5">
@@ -82,21 +82,21 @@ const triggerMassAssignmentHoneypot = async () => {
</div>
<!-- Tests terminés -->
<div class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-emerald-500/10 transition-all duration-300 relative overflow-hidden group">
<div v-if="user.role !== 'gestionnaire_rh'" class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-emerald-500/10 transition-all duration-300 relative overflow-hidden group">
<div class="text-[10px] font-subtitle font-black uppercase tracking-widest text-anthracite/40">Tests terminés</div>
<div class="text-4xl font-black mt-3 text-emerald-500">{{ stats.finished_tests }}</div>
<div class="absolute bottom-0 right-0 w-24 h-24 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-emerald-500/10 to-transparent"></div>
</div>
<!-- Moyenne Générale -->
<div class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-sky/10 transition-all duration-300 relative overflow-hidden group">
<div v-if="user.role !== 'gestionnaire_rh'" class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-sky/10 transition-all duration-300 relative overflow-hidden group">
<div class="text-[10px] font-subtitle font-black uppercase tracking-widest text-anthracite/40">Moyenne Générale</div>
<div class="text-4xl font-black mt-3 text-sky">{{ stats.average_score }} <span class="text-lg opacity-50 font-bold">/ 20</span></div>
<div class="absolute bottom-0 right-0 w-24 h-24 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-sky/10 to-transparent"></div>
</div>
<!-- Meilleur Score -->
<div class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-accent/10 transition-all duration-300 relative overflow-hidden group">
<div v-if="user.role !== 'gestionnaire_rh'" class="bg-white p-6 rounded-3xl shadow-sm border border-anthracite/5 hover:-translate-y-1 hover:shadow-xl hover:shadow-accent/10 transition-all duration-300 relative overflow-hidden group">
<div class="text-[10px] font-subtitle font-black uppercase tracking-widest text-anthracite/40">Meilleur Score</div>
<div class="text-4xl font-black mt-3 text-accent">{{ stats.best_score }} <span class="text-lg opacity-50 font-bold">/ 20</span></div>
<div class="absolute bottom-0 right-0 w-24 h-24 bg-[radial-gradient(ellipse_at_bottom_right,_var(--tw-gradient-stops))] from-accent/10 to-transparent"></div>
@@ -108,7 +108,7 @@ const triggerMassAssignmentHoneypot = async () => {
<div class="px-8 py-6 border-b border-anthracite/5 flex justify-between items-center bg-sand/30">
<h3 class="text-xl font-serif font-black text-primary capitalize tracking-tight flex items-center gap-3">
<div class="w-1.5 h-6 bg-highlight rounded-full hidden md:block"></div>
Top 10 Candidats
{{ user.role === 'gestionnaire_rh' ? 'Dernières candidatures' : 'Top 10 Candidats' }}
</h3>
<Link :href="route('admin.candidates.index')" class="text-xs font-subtitle font-bold uppercase tracking-widest text-primary hover:text-highlight transition-colors flex items-center gap-1">
Voir tous <span class="hidden sm:inline">les candidats</span> &rarr;
@@ -119,8 +119,8 @@ const triggerMassAssignmentHoneypot = async () => {
<thead>
<tr class="bg-neutral/50">
<th class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Candidat</th>
<th class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Score Pondéré</th>
<th class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Adéquation IA</th>
<th v-if="user.role !== 'gestionnaire_rh'" class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Score Pondéré</th>
<th v-if="user.role !== 'gestionnaire_rh'" class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Adéquation IA</th>
<th class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40">Statut</th>
<th class="px-8 py-4 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40 text-right">Actions</th>
</tr>
@@ -131,12 +131,12 @@ const triggerMassAssignmentHoneypot = async () => {
<div class="font-bold text-primary group-hover:text-highlight transition-colors block">{{ candidate.name }}</div>
<div class="text-xs text-anthracite/50 font-subtitle tracking-wide mt-0.5">{{ candidate.email }}</div>
</td>
<td class="px-8 py-5">
<td v-if="user.role !== 'gestionnaire_rh'" class="px-8 py-5">
<div class="inline-flex items-center gap-2 px-4 py-1.5 bg-primary/5 text-primary rounded-xl font-black text-sm border border-primary/10 shadow-sm">
{{ candidate.weighted_score }} <span class="opacity-50 text-xs">/ 20</span>
</div>
</td>
<td class="px-8 py-5">
<td v-if="user.role !== 'gestionnaire_rh'" class="px-8 py-5">
<div v-if="candidate.ai_analysis" class="flex items-center gap-2">
<div
class="px-3 py-1 rounded-lg text-xs font-black shadow-sm"