Admin: implementation of the 'is_selected' feature for candidates for interviews
This commit is contained in:
@@ -43,10 +43,14 @@ const submit = () => {
|
||||
|
||||
const deleteCandidate = (id) => {
|
||||
if (confirm('Voulez-vous vraiment supprimer ce candidat ?')) {
|
||||
router.delete(route('admin.candidates.destroy', id));
|
||||
router.delete(route('admin.candidates.destroy', id), { preserveScroll: true });
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSelection = (id) => {
|
||||
router.patch(route('admin.candidates.toggle-selection', id), {}, { preserveScroll: true });
|
||||
};
|
||||
|
||||
const openPreview = (doc) => {
|
||||
selectedDocument.value = doc;
|
||||
};
|
||||
@@ -69,11 +73,24 @@ const getNestedValue = (obj, path) => {
|
||||
};
|
||||
|
||||
const selectedJobPosition = ref('');
|
||||
const showOnlySelected = ref(false);
|
||||
|
||||
const filteredCandidates = computed(() => {
|
||||
if (selectedJobPosition.value === '') return props.candidates;
|
||||
if (selectedJobPosition.value === 'none') return props.candidates.filter(c => !c.job_position_id);
|
||||
return props.candidates.filter(c => c.job_position_id === selectedJobPosition.value);
|
||||
let result = props.candidates;
|
||||
|
||||
if (showOnlySelected.value) {
|
||||
result = result.filter(c => c.is_selected);
|
||||
}
|
||||
|
||||
if (selectedJobPosition.value !== '') {
|
||||
if (selectedJobPosition.value === 'none') {
|
||||
result = result.filter(c => !c.job_position_id);
|
||||
} else {
|
||||
result = result.filter(c => c.job_position_id === selectedJobPosition.value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
const sortedCandidates = computed(() => {
|
||||
@@ -102,18 +119,26 @@ const sortedCandidates = computed(() => {
|
||||
<div class="flex justify-between items-end mb-8">
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-2xl font-bold">Liste des Candidats</h3>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="text-sm font-medium text-slate-700 dark:text-slate-300">Filtrer par fiche de poste :</label>
|
||||
<select
|
||||
v-model="selectedJobPosition"
|
||||
class="block w-64 rounded-xl border-slate-300 dark:border-slate-700 dark:bg-slate-900 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
>
|
||||
<option value="">Toutes les fiches de poste</option>
|
||||
<option value="none">➜ Non assigné (Candidature Spontanée)</option>
|
||||
<option v-for="jp in jobPositions" :key="jp.id" :value="jp.id">
|
||||
{{ jp.title }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-3 bg-white dark:bg-slate-800 p-2 rounded-xl border border-slate-200 dark:border-slate-700 shadow-sm">
|
||||
<label class="flex items-center gap-2 cursor-pointer px-2">
|
||||
<input type="checkbox" v-model="showOnlySelected" class="rounded border-amber-300 text-amber-500 focus:ring-amber-500/20 cursor-pointer">
|
||||
<span class="text-sm font-bold text-slate-700 dark:text-slate-300">Retenus uniquement</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="text-sm font-medium text-slate-700 dark:text-slate-300">Filtrer par fiche de poste :</label>
|
||||
<select
|
||||
v-model="selectedJobPosition"
|
||||
class="block w-64 rounded-xl border-slate-300 dark:border-slate-700 dark:bg-slate-900 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
>
|
||||
<option value="">Toutes les fiches de poste</option>
|
||||
<option value="none">➜ Non assigné (Candidature Spontanée)</option>
|
||||
<option v-for="jp in jobPositions" :key="jp.id" :value="jp.id">
|
||||
{{ jp.title }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PrimaryButton @click="isModalOpen = true">
|
||||
@@ -139,6 +164,7 @@ const sortedCandidates = computed(() => {
|
||||
<table class="w-full text-left">
|
||||
<thead class="bg-slate-50 dark:bg-slate-700/50 border-b border-slate-200 dark:border-slate-700">
|
||||
<tr>
|
||||
<th class="w-12 px-6 py-4"></th>
|
||||
<th @click="sortBy('user.name')" class="px-6 py-4 font-semibold text-slate-700 dark:text-slate-300 cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-700/50 transition-colors">
|
||||
<div class="flex items-center gap-2">
|
||||
Nom
|
||||
@@ -201,6 +227,16 @@ const sortedCandidates = computed(() => {
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200 dark:divide-slate-700">
|
||||
<tr v-for="candidate in sortedCandidates" :key="candidate.id" class="hover:bg-slate-50/50 dark:hover:bg-slate-700/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<button @click="toggleSelection(candidate.id)" class="text-amber-400 hover:text-amber-500 hover:scale-110 transition-transform focus:outline-none" :title="candidate.is_selected ? 'Retirer des retenus' : 'Marquer comme retenu'">
|
||||
<svg v-if="candidate.is_selected" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-slate-300 hover:text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="font-bold text-slate-900 dark:text-white">{{ candidate.user.name }}</div>
|
||||
<div class="text-[10px] text-slate-500 font-bold uppercase tracking-tight">{{ candidate.phone }}</div>
|
||||
@@ -294,7 +330,7 @@ const sortedCandidates = computed(() => {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="candidates.length === 0">
|
||||
<td colspan="7" class="px-6 py-12 text-center text-slate-500 italic">
|
||||
<td colspan="8" class="px-6 py-12 text-center text-slate-500 italic">
|
||||
Aucun candidat trouvé.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user