Enhance candidates management: add city field, drag-and-drop ranking persistence, AI analysis popover, and CV preview

This commit is contained in:
mrKamoo
2026-04-22 15:26:15 +02:00
parent 174f229b5d
commit 6f00da6d10
13 changed files with 480 additions and 116 deletions

View File

@@ -26,7 +26,8 @@ const form = useForm({
name: '',
email: '',
phone: '',
linkedin_url: '',
linkedin_url: '',
city: '',
cv: null,
cover_letter: null,
tenant_id: '',
@@ -272,6 +273,12 @@ const batchAnalyze = async () => {
<svg v-show="sortKey === 'tenant.name'" xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" :class="{ 'rotate-180': sortOrder === -1 }" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>
</div>
</th>
<th @click="sortBy('city')" class="px-8 py-5 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40 cursor-pointer hover:text-primary transition-colors">
<div class="flex items-center gap-2">
Ville
<svg v-show="sortKey === 'city'" xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" :class="{ 'rotate-180': sortOrder === -1 }" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>
</div>
</th>
<th @click="sortBy('job_position.title')" class="px-8 py-5 text-[10px] font-subtitle font-black uppercase tracking-[0.2em] text-anthracite/40 cursor-pointer hover:text-primary transition-colors">
<div class="flex items-center gap-2">
Poste Ciblé
@@ -332,6 +339,9 @@ const batchAnalyze = async () => {
<td class="px-8 py-5 text-[10px] font-black uppercase tracking-widest text-primary/60" v-if="$page.props.auth.user.role === 'super_admin'">
{{ candidate.tenant ? candidate.tenant.name : 'Aucune' }}
</td>
<td class="px-8 py-5 text-[10px] font-black uppercase tracking-widest text-anthracite/60">
{{ candidate.city || '--' }}
</td>
<td class="px-8 py-5 text-xs font-bold text-anthracite">
{{ candidate.job_position ? candidate.job_position.title : 'Non assigné' }}
</td>
@@ -358,8 +368,8 @@ const batchAnalyze = async () => {
<div
class="px-2 py-0.5 rounded-lg text-[10px] font-black shadow-sm"
:class="[
candidate.ai_analysis.match_score >= 80 ? 'bg-emerald-50 text-emerald-700 border border-emerald-200' :
candidate.ai_analysis.match_score >= 60 ? 'bg-highlight/10 text-[#3a2800] border border-highlight/30' :
candidate.ai_analysis.match_score >= 90 ? 'bg-emerald-50 text-emerald-700 border border-emerald-200' :
candidate.ai_analysis.match_score >= 80 ? 'bg-highlight/10 text-[#3a2800] border border-highlight/30' :
'bg-accent/10 text-accent border border-accent/20'
]"
>
@@ -396,7 +406,7 @@ const batchAnalyze = async () => {
</td>
</tr>
<tr v-if="candidates.length === 0">
<td colspan="11" class="px-8 py-16 text-center">
<td colspan="12" class="px-8 py-16 text-center">
<div class="text-anthracite/40 italic font-medium font-subtitle">
Aucun candidat trouvé.
</div>
@@ -432,6 +442,14 @@ const batchAnalyze = async () => {
<TextInput id="phone" type="text" class="mt-1 block w-full" v-model="form.phone" />
<InputError class="mt-2" :message="form.errors.phone" />
</div>
<div>
<InputLabel for="city" value="Ville" />
<TextInput id="city" type="text" class="mt-1 block w-full" v-model="form.city" />
<InputError class="mt-2" :message="form.errors.city" />
</div>
</div>
<div class="grid grid-cols-1 gap-4">
<div>
<InputLabel for="linkedin_url" value="LinkedIn URL" />
<TextInput id="linkedin_url" type="url" class="mt-1 block w-full" v-model="form.linkedin_url" />