344 lines
17 KiB
TypeScript
344 lines
17 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState } from 'react';
|
|
import { Briefcase, ChevronDown, Search } from 'lucide-react';
|
|
|
|
const euro = (n: number) => new Intl.NumberFormat('fr-FR', {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
}).format(n) + '€';
|
|
|
|
// Données des minima par groupe et échelon
|
|
const minimaData = {
|
|
'Groupe 1': [3495.87, 3600.75, 3705.62, 3810.50, 3915.37, 4020.25, 4125.13, 4230.00, 4334.88, 4439.75, 4544.63, 4649.51],
|
|
'Groupe 2': [2734.91, 2816.96, 2899.00, 2981.05, 3063.10, 3145.15, 3227.19, 3309.24, 3391.29, 3473.34, 3555.38, 3637.43],
|
|
'Groupe 3': [2522.44, 2598.11, 2673.79, 2749.46, 2825.13, 2900.81, 2976.48, 3052.15, 3127.83, 3203.50, 3279.17, 3354.85],
|
|
'Groupe 4': [2324.51, 2394.25, 2463.98, 2533.72, 2603.45, 2673.19, 2742.92, 2812.66, 2882.39, 2952.13, 3021.86, 3091.60],
|
|
'Groupe 5': [1991.44, 2051.18, 2110.93, 2170.67, 2230.41, 2290.16, 2349.90, 2409.64, 2469.39, 2529.13, 2588.87, 2648.62],
|
|
'Groupe 6': [1870.99, 1927.12, 1983.25, 2039.38, 2095.51, 2151.64, 2207.77, 2263.90, 2320.03, 2376.16, 2432.29, 2488.42],
|
|
'Groupe 7': [1811.69, 1866.04, 1920.39, 1974.74, 2029.09, 2083.44, 2137.79, 2192.14, 2246.50, 2300.85, 2355.20, 2409.55],
|
|
'Groupe 8': [1784.42, 1837.95, 1891.49, 1945.02, 1998.55, 2052.08, 2105.62, 2159.15, 2212.68, 2266.21, 2319.75, 2373.28],
|
|
'Groupe 9': [1770.58, 1823.70, 1876.81, 1929.93, 1983.05, 2036.17, 2089.28, 2142.40, 2195.52, 2248.64, 2301.75, 2354.87],
|
|
};
|
|
|
|
// Liste des professions et leurs groupes
|
|
const professionsData = [
|
|
{ profession: "Directeur", groupe: 1 },
|
|
{ profession: "Administrateur", groupe: 2 },
|
|
{ profession: "Secrétaire Général", groupe: 3 },
|
|
{ profession: "Directeur de Production", groupe: 3 },
|
|
{ profession: "Conseiller Technique", groupe: 4 },
|
|
{ profession: "Responsable d'Administration", groupe: 4 },
|
|
{ profession: "Chef Comptable", groupe: 4 },
|
|
{ profession: "Collaborateur de Direction", groupe: 4 },
|
|
{ profession: "Administrateur de Production", groupe: 4 },
|
|
{ profession: "Administrateur de Diffusion", groupe: 4 },
|
|
{ profession: "Programmateur Artistique", groupe: 4 },
|
|
{ profession: "Secrétaire de Direction", groupe: 5 },
|
|
{ profession: "Comptable Principal", groupe: 5 },
|
|
{ profession: "Chargé de Production", groupe: 5 },
|
|
{ profession: "Chargé de Diffusion", groupe: 5 },
|
|
{ profession: "Bibliothécaire Musical", groupe: 5 },
|
|
{ profession: "Copiste", groupe: 5 },
|
|
{ profession: "Attaché de Programmation", groupe: 6 },
|
|
{ profession: "Attaché de Production", groupe: 6 },
|
|
{ profession: "Attaché de Diffusion", groupe: 6 },
|
|
{ profession: "Attaché d'Administration", groupe: 6 },
|
|
{ profession: "Comptable", groupe: 7 },
|
|
{ profession: "Secrétaire", groupe: 8 },
|
|
{ profession: "Secrétaire-Comptable", groupe: 8 },
|
|
{ profession: "Aide-Comptable", groupe: 9 },
|
|
{ profession: "Caissier", groupe: 9 },
|
|
{ profession: "Standardiste", groupe: 9 },
|
|
{ profession: "Employé de Bureau", groupe: 9 },
|
|
{ profession: "Agent de Catering", groupe: 9 },
|
|
{ profession: "Directeur de la Communication", groupe: 3 },
|
|
{ profession: "Directeur des Relations Publiques", groupe: 3 },
|
|
{ profession: "Directeur de l'Action Culturelle", groupe: 3 },
|
|
{ profession: "Responsable des relations avec la presse", groupe: 4 },
|
|
{ profession: "Responsable de Formation", groupe: 4 },
|
|
{ profession: "Responsable de l'Action Culturelle", groupe: 4 },
|
|
{ profession: "Responsable du secteur de l'information", groupe: 4 },
|
|
{ profession: "Chargé du secteur des relations avec le public", groupe: 5 },
|
|
{ profession: "Attaché à l'Accueil", groupe: 6 },
|
|
{ profession: "Attaché à l'information", groupe: 6 },
|
|
{ profession: "Attaché aux relations avec le public", groupe: 6 },
|
|
{ profession: "Attaché à l'accompagnement des pratiques artistiques et culturelles", groupe: 6 },
|
|
{ profession: "Graphiste ou Infographiste", groupe: 6 },
|
|
{ profession: "Documentaliste", groupe: 7 },
|
|
{ profession: "Maquettiste PAO", groupe: 7 },
|
|
{ profession: "Caissier-hôte d'accueil", groupe: 8 },
|
|
{ profession: "Hôte(sse) d'accueil", groupe: 9 },
|
|
{ profession: "Contrôleur", groupe: 9 },
|
|
{ profession: "Hôte(sse) de salle", groupe: 9 },
|
|
{ profession: "Employé de routage", groupe: 9 },
|
|
{ profession: "Employé de bar", groupe: 9 },
|
|
{ profession: "Directeur technique", groupe: 3 },
|
|
{ profession: "Scénographe", groupe: 3 },
|
|
{ profession: "Régisseur général", groupe: 4 },
|
|
{ profession: "Concepteur", groupe: 4 },
|
|
{ profession: "Eclairagiste", groupe: 4 },
|
|
{ profession: "Concepteur lumière", groupe: 4 },
|
|
{ profession: "Ingénieur du son", groupe: 4 },
|
|
{ profession: "Concepteur des costumes", groupe: 4 },
|
|
{ profession: "Concepteur des maquillages", groupe: 4 },
|
|
{ profession: "Concepteur des perruques", groupe: 4 },
|
|
{ profession: "Concepteur des coiffures", groupe: 4 },
|
|
{ profession: "Concepteur des artifices", groupe: 4 },
|
|
{ profession: "Décorateur", groupe: 4 },
|
|
{ profession: "Pyrotechnicien", groupe: 4 },
|
|
{ profession: "Concepteur images-vidéo", groupe: 4 },
|
|
{ profession: "Concepteur de structure scénique ou acrobatique", groupe: 4 },
|
|
{ profession: "Réalisateur des costumes", groupe: 5 },
|
|
{ profession: "Réalisateur des chapeaux", groupe: 5 },
|
|
{ profession: "Réalisateur des maquillages", groupe: 5 },
|
|
{ profession: "Réalisateur des masques", groupe: 5 },
|
|
{ profession: "Réalisateur des coiffures", groupe: 5 },
|
|
{ profession: "Réalisateur des perruques", groupe: 5 },
|
|
{ profession: "Réalisateur son", groupe: 5 },
|
|
{ profession: "Réalisateur lumière", groupe: 5 },
|
|
{ profession: "Réalisateur pyrotechnique", groupe: 5 },
|
|
{ profession: "Réalisateur de décor", groupe: 5 },
|
|
{ profession: "Réalisateur de structure scénique ou acrobatique", groupe: 5 },
|
|
{ profession: "Réalisateur d'accessoires", groupe: 5 },
|
|
{ profession: "Régisseur principal ou de site", groupe: 5 },
|
|
{ profession: "Régisseur de structure mobile, acrobatique ou scénique", groupe: 5 },
|
|
{ profession: "Régisseur de scène ou de plateau", groupe: 6 },
|
|
{ profession: "Régisseur d'orchestre", groupe: 6 },
|
|
{ profession: "Régisseur de choeurs", groupe: 6 },
|
|
{ profession: "Régisseur lumière", groupe: 6 },
|
|
{ profession: "Régisseur son", groupe: 6 },
|
|
{ profession: "Régisseur de lieux de répétition", groupe: 6 },
|
|
{ profession: "Régisseur audiovisuel-vidéo de spectacle", groupe: 6 },
|
|
{ profession: "Régisseur de production", groupe: 6 },
|
|
{ profession: "Technicien de réalisation", groupe: 6 },
|
|
{ profession: "Tapissier de théâtre", groupe: 6 },
|
|
{ profession: "Ensemblier", groupe: 6 },
|
|
{ profession: "Menuisier de théâtre", groupe: 6 },
|
|
{ profession: "Peintre décorateur", groupe: 6 },
|
|
{ profession: "Peintre de théâtre", groupe: 6 },
|
|
{ profession: "Sculpteur de théâtre", groupe: 6 },
|
|
{ profession: "Serrurier", groupe: 6 },
|
|
{ profession: "Serrurier métallier", groupe: 6 },
|
|
{ profession: "Staffeur", groupe: 6 },
|
|
{ profession: "Chef-machiniste", groupe: 6 },
|
|
{ profession: "Dessinateur DAO-CAO", groupe: 7 },
|
|
{ profession: "Constructeur", groupe: 7 },
|
|
{ profession: "Machiniste", groupe: 7 },
|
|
{ profession: "Opérateur projectionniste", groupe: 7 },
|
|
{ profession: "Electricien", groupe: 7 },
|
|
{ profession: "Technicien hydraulique-de structure", groupe: 7 },
|
|
{ profession: "Technicien lumière", groupe: 7 },
|
|
{ profession: "Technicien son", groupe: 7 },
|
|
{ profession: "Technicien console", groupe: 7 },
|
|
{ profession: "Technicien vidéo", groupe: 7 },
|
|
{ profession: "Technicien image", groupe: 7 },
|
|
{ profession: "Technicien effets spéciaux", groupe: 7 },
|
|
{ profession: "Technicien groupe électrogène", groupe: 7 },
|
|
{ profession: "Technicien instruments", groupe: 7 },
|
|
{ profession: "Technicien de sécurité", groupe: 7 },
|
|
{ profession: "Monteur de structure mobile", groupe: 8 },
|
|
{ profession: "Monteur de structure acrobatique ou scénique", groupe: 8 },
|
|
{ profession: "Assistant instrument de musique (backline)", groupe: 8 },
|
|
{ profession: "Cintrier", groupe: 8 },
|
|
{ profession: "Ouvrier professionnel", groupe: 8 },
|
|
{ profession: "Ouvrier son", groupe: 8 },
|
|
{ profession: "Ouvrier prompteur", groupe: 8 },
|
|
{ profession: "Ouvrier lumière-poursuiteur", groupe: 8 },
|
|
{ profession: "Ouvrier vidéo-images", groupe: 8 },
|
|
{ profession: "Ouvrier accrocheur (rigger)", groupe: 8 },
|
|
{ profession: "Perruquier", groupe: 8 },
|
|
{ profession: "Chapelier", groupe: 8 },
|
|
{ profession: "Bottier", groupe: 8 },
|
|
{ profession: "Maquilleur", groupe: 8 },
|
|
{ profession: "Posticheur", groupe: 8 },
|
|
{ profession: "Coiffeur", groupe: 8 },
|
|
{ profession: "Habilleur", groupe: 8 },
|
|
{ profession: "Armurier", groupe: 8 },
|
|
{ profession: "Artificier", groupe: 8 },
|
|
{ profession: "Accessoiriste", groupe: 8 },
|
|
{ profession: "Lingère", groupe: 8 },
|
|
{ profession: "Repasseur·se", groupe: 8 },
|
|
{ profession: "Retoucheur·se", groupe: 8 },
|
|
{ profession: "Chauffeur-coursier", groupe: 9 },
|
|
{ profession: "Employé de nettoyage", groupe: 9 },
|
|
{ profession: "Gardien", groupe: 9 },
|
|
{ profession: "Employé polyvalent", groupe: 9 },
|
|
];
|
|
|
|
export default function EmploisNonArtistiquesContent() {
|
|
const [selectedGroupe, setSelectedGroupe] = useState<string>('Groupe 1');
|
|
const [searchTerm, setSearchTerm] = useState<string>('');
|
|
const [searchResults, setSearchResults] = useState<typeof professionsData>([]);
|
|
const [selectedProfession, setSelectedProfession] = useState<string>('');
|
|
|
|
const handleSearch = (term: string) => {
|
|
setSearchTerm(term);
|
|
if (term.trim() === '') {
|
|
setSearchResults([]);
|
|
return;
|
|
}
|
|
|
|
const results = professionsData.filter(item =>
|
|
item.profession.toLowerCase().includes(term.toLowerCase())
|
|
);
|
|
setSearchResults(results);
|
|
};
|
|
|
|
const selectProfession = (profession: string, groupe: number) => {
|
|
setSelectedGroupe(`Groupe ${groupe}`);
|
|
setSelectedProfession(profession);
|
|
setSearchTerm('');
|
|
setSearchResults([]);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* En-tête */}
|
|
<div className="rounded-xl border bg-gradient-to-br from-slate-50 to-gray-50 p-4">
|
|
<h2 className="text-lg font-semibold text-slate-900 mb-1">
|
|
Emplois non artistiques
|
|
</h2>
|
|
<p className="text-sm text-slate-700">
|
|
Minima mensuels conventionnels pour les emplois administratifs, techniques et commerciaux
|
|
</p>
|
|
<p className="text-xs text-slate-600 mt-2">
|
|
Grille de salaires applicable au 1er juin 2024
|
|
</p>
|
|
</div>
|
|
|
|
{/* Recherche et sélection côte à côte */}
|
|
<div className="rounded-xl border bg-white p-5">
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
{/* Moteur de recherche de profession */}
|
|
<div>
|
|
<label htmlFor="profession-search" className="block text-sm font-semibold text-slate-900 mb-3 flex items-center gap-2">
|
|
<Search className="w-4 h-4" />
|
|
Rechercher une profession
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
id="profession-search"
|
|
type="text"
|
|
value={searchTerm}
|
|
onChange={(e) => handleSearch(e.target.value)}
|
|
placeholder="Tapez le nom d'une profession..."
|
|
className="w-full px-4 py-3 pl-10 rounded-lg border-2 border-slate-200 bg-white text-slate-900 placeholder:text-slate-400 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 transition-all"
|
|
/>
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
</div>
|
|
|
|
{/* Résultats de recherche */}
|
|
{searchResults.length > 0 && (
|
|
<div className="mt-3 border border-slate-200 rounded-lg divide-y divide-slate-100 max-h-60 overflow-y-auto shadow-lg">
|
|
{searchResults.map((result, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => selectProfession(result.profession, result.groupe)}
|
|
className="w-full px-4 py-3 text-left hover:bg-indigo-50 transition-colors flex items-center justify-between group"
|
|
>
|
|
<span className="text-sm text-slate-900 font-medium">{result.profession}</span>
|
|
<span className="text-xs font-bold text-indigo-600 bg-indigo-100 px-2 py-1 rounded group-hover:bg-indigo-200">
|
|
Groupe {result.groupe}
|
|
</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{searchTerm && searchResults.length === 0 && (
|
|
<div className="mt-3 p-4 bg-amber-50 border border-amber-200 rounded-lg">
|
|
<p className="text-sm text-amber-800">
|
|
Aucune profession trouvée pour "{searchTerm}".
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Profession sélectionnée */}
|
|
{selectedProfession && (
|
|
<div className="mt-3 p-3 bg-green-50 border border-green-200 rounded-lg">
|
|
<p className="text-xs text-green-700 font-medium mb-1">Profession sélectionnée :</p>
|
|
<p className="text-sm text-green-900 font-bold">{selectedProfession}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Sélecteur de groupe */}
|
|
<div>
|
|
<label htmlFor="groupe-select" className="block text-sm font-semibold text-slate-900 mb-3">
|
|
Ou sélectionnez directement un groupe :
|
|
</label>
|
|
<div className="relative">
|
|
<select
|
|
id="groupe-select"
|
|
value={selectedGroupe}
|
|
onChange={(e) => {
|
|
setSelectedGroupe(e.target.value);
|
|
setSelectedProfession('');
|
|
}}
|
|
className="w-full appearance-none px-4 py-3 pr-10 rounded-lg border-2 border-slate-200 bg-white text-slate-900 font-semibold focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 transition-all cursor-pointer"
|
|
>
|
|
{Object.keys(minimaData).map((groupe) => (
|
|
<option key={groupe} value={groupe}>
|
|
{groupe}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 pointer-events-none" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tableau des minima pour le groupe sélectionné */}
|
|
<div className="rounded-xl border bg-white p-5">
|
|
<h3 className="text-base font-bold text-indigo-900 mb-4 flex items-center gap-2">
|
|
<Briefcase className="w-5 h-5" />
|
|
Minima mensuels - {selectedGroupe}
|
|
</h3>
|
|
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full text-xs border-collapse">
|
|
<thead>
|
|
<tr className="bg-indigo-50">
|
|
<th className="text-left p-3 text-indigo-900 font-bold border border-indigo-200"></th>
|
|
{Array.from({ length: 12 }, (_, i) => (
|
|
<th key={i + 1} className="text-center p-3 text-indigo-900 font-bold border border-indigo-200">
|
|
Échelon {i + 1}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr className="hover:bg-indigo-50/30">
|
|
<td className="p-3 border border-indigo-200 font-semibold text-indigo-900">Mensuel</td>
|
|
{minimaData[selectedGroupe as keyof typeof minimaData].map((montant, index) => (
|
|
<td key={index} className="text-center p-3 font-bold text-indigo-900 border border-indigo-200 bg-indigo-50/50">
|
|
{euro(montant)}
|
|
</td>
|
|
))}
|
|
</tr>
|
|
<tr className="hover:bg-indigo-50/30">
|
|
<td className="p-3 border border-indigo-200 font-semibold text-indigo-900">Taux horaire</td>
|
|
{minimaData[selectedGroupe as keyof typeof minimaData].map((montant, index) => (
|
|
<td key={index} className="text-center p-3 font-semibold text-indigo-700 border border-indigo-200">
|
|
{euro(montant / 151.4)}
|
|
</td>
|
|
))}
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{/* Note explicative */}
|
|
<div className="mt-4 p-3 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<p className="text-xs text-blue-900">
|
|
<span className="font-semibold">💡 Note :</span> Ces montants correspondent aux salaires mensuels minimaux bruts
|
|
pour les emplois non artistiques selon la classification conventionnelle CCNEAC.
|
|
Chaque groupe comporte 12 échelons représentant une progression salariale.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|