308 lines
11 KiB
TypeScript
308 lines
11 KiB
TypeScript
"use client";
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import { usePageTitle } from '@/hooks/usePageTitle';
|
|
import Link from 'next/link';
|
|
import { ArrowLeft, Scale, Calculator, X } from 'lucide-react';
|
|
import ArtistesDramatiquesContent from './artistes-dramatiques-data';
|
|
import ArtistesMusiciensContent from './artistes-musiciens-data';
|
|
import ArtistesLyriquesContent from './artistes-lyriques-data';
|
|
import ArtistesCirqueContent from './artistes-cirque-data';
|
|
import EmploisNonArtistiquesContent from './emplois-non-artistiques-data';
|
|
import SimulateurContent from '@/components/simulateur/SimulateurContent';
|
|
import CalculatorComponent from '@/components/Calculator';
|
|
import { useDraggableModal } from '@/hooks/useDraggableModal';
|
|
|
|
export default function CCNEACPage() {
|
|
usePageTitle("Minima CCNEAC");
|
|
const [isSimulateurOpen, setIsSimulateurOpen] = useState(false);
|
|
const [isCalculatorOpen, setIsCalculatorOpen] = useState(false);
|
|
const [modalPosition, setModalPosition] = useState({ x: 0, y: 0 });
|
|
const modalRef = React.useRef<HTMLDivElement>(null);
|
|
|
|
|
|
// Gestion du drag & drop du modal
|
|
const { onPointerDown, onPointerMove, onPointerUp } = useDraggableModal(
|
|
modalRef,
|
|
setModalPosition,
|
|
{ constrainToViewport: true, disableIframeDuringDrag: true }
|
|
);
|
|
|
|
// Écouter les messages de l'iframe pour ouvrir la calculatrice
|
|
useEffect(() => {
|
|
const handleMessage = (event: MessageEvent) => {
|
|
if (event.data?.type === 'openCalculator') {
|
|
setIsCalculatorOpen(true);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('message', handleMessage);
|
|
return () => window.removeEventListener('message', handleMessage);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// Script de gestion des onglets
|
|
const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
|
|
const panels = Array.from(document.querySelectorAll('.ccneac-panel'));
|
|
|
|
function activateTab(tab: Element) {
|
|
tabs.forEach((t) => {
|
|
const selected = t === tab;
|
|
t.setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
(t as HTMLElement).tabIndex = selected ? 0 : -1;
|
|
});
|
|
|
|
panels.forEach((p) => {
|
|
const active = p.id === tab.getAttribute('aria-controls');
|
|
p.classList.toggle('active', active);
|
|
if (active) {
|
|
p.removeAttribute('hidden');
|
|
} else {
|
|
p.setAttribute('hidden', '');
|
|
}
|
|
});
|
|
|
|
(tab as HTMLElement).focus({ preventScroll: true });
|
|
}
|
|
|
|
tabs.forEach((tab) => {
|
|
tab.addEventListener('click', () => activateTab(tab));
|
|
});
|
|
|
|
// Navigation clavier
|
|
document.addEventListener('keydown', (e) => {
|
|
const current = document.querySelector('[role="tab"][aria-selected="true"]');
|
|
if (!current) return;
|
|
const i = tabs.indexOf(current);
|
|
if (e.key === 'ArrowRight') {
|
|
e.preventDefault();
|
|
activateTab(tabs[(i + 1) % tabs.length]);
|
|
}
|
|
if (e.key === 'ArrowLeft') {
|
|
e.preventDefault();
|
|
activateTab(tabs[(i - 1 + tabs.length) % tabs.length]);
|
|
}
|
|
if (e.key === 'Home') {
|
|
e.preventDefault();
|
|
activateTab(tabs[0]);
|
|
}
|
|
if (e.key === 'End') {
|
|
e.preventDefault();
|
|
activateTab(tabs[tabs.length - 1]);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<style jsx global>{`
|
|
.ccneac-tabs [role="tablist"] {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.ccneac-tabs [role="tab"] {
|
|
appearance: none;
|
|
border: 1px solid #e2e8f0;
|
|
background: white;
|
|
border-radius: 999px;
|
|
padding: 9px 16px;
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
color: #475569;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.ccneac-tabs [role="tab"]:hover {
|
|
background: #f8fafc;
|
|
border-color: #cbd5e1;
|
|
}
|
|
|
|
.ccneac-tabs [role="tab"][aria-selected="true"] {
|
|
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
|
border-color: #8b5cf6;
|
|
color: white;
|
|
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
|
}
|
|
|
|
.ccneac-tabs [role="tab"]:focus-visible {
|
|
outline: 2px solid #6366f1;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.ccneac-panel {
|
|
display: none;
|
|
}
|
|
|
|
.ccneac-panel.active {
|
|
display: block;
|
|
}
|
|
`}</style>
|
|
|
|
{/* Navigation retour */}
|
|
<Link
|
|
href="/minima-ccn"
|
|
className="inline-flex items-center gap-2 text-sm text-slate-600 hover:text-slate-900 transition-colors"
|
|
>
|
|
<ArrowLeft className="w-4 h-4" />
|
|
Retour aux minima CCN
|
|
</Link>
|
|
|
|
{/* En-tête */}
|
|
<section className="rounded-2xl border bg-white p-6">
|
|
<div className="flex items-start gap-3">
|
|
<div className="flex-shrink-0 w-12 h-12 rounded-xl bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center">
|
|
<Scale className="w-6 h-6 text-white" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<h1 className="text-2xl font-semibold text-slate-900">CCNEAC (IDCC 1285)</h1>
|
|
<span className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold bg-gradient-to-r from-emerald-500 to-emerald-600 text-white shadow-sm">
|
|
À jour 2025
|
|
</span>
|
|
</div>
|
|
<p className="text-sm text-slate-600 mb-2">
|
|
Convention Collective Nationale des Entreprises Artistiques et Culturelles
|
|
</p>
|
|
<p className="text-xs text-slate-500">
|
|
Données issues de l'accord sur les salaires signé le 2 mai 2024, applicable au 1er juin 2024, étendu par arrêté du 23 juillet 2024.
|
|
<br />
|
|
Toujours en vigueur au 2e semestre 2025. <strong>Tous les montants sont exprimés bruts.</strong>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Onglets */}
|
|
<section className="rounded-2xl border bg-white p-6 ccneac-tabs">
|
|
<p className="text-sm text-slate-600 mb-4">
|
|
Cliquez sur un onglet pour accéder aux minima par catégorie d'artistes ou de personnel.
|
|
</p>
|
|
|
|
<div role="tablist" aria-label="Onglets CCNEAC">
|
|
<button
|
|
role="tab"
|
|
aria-selected="true"
|
|
aria-controls="ccneac-artistes-dramatiques"
|
|
tabIndex={0}
|
|
>
|
|
Artistes dramatiques et chorégraphiques
|
|
</button>
|
|
<button
|
|
role="tab"
|
|
aria-selected="false"
|
|
aria-controls="ccneac-artistes-musiciens"
|
|
tabIndex={-1}
|
|
>
|
|
Artistes musiciens
|
|
</button>
|
|
<button
|
|
role="tab"
|
|
aria-selected="false"
|
|
aria-controls="ccneac-artistes-lyriques"
|
|
tabIndex={-1}
|
|
>
|
|
Artistes lyriques
|
|
</button>
|
|
<button
|
|
role="tab"
|
|
aria-selected="false"
|
|
aria-controls="ccneac-artistes-cirque"
|
|
tabIndex={-1}
|
|
>
|
|
Artistes de cirque
|
|
</button>
|
|
<button
|
|
role="tab"
|
|
aria-selected="false"
|
|
aria-controls="ccneac-emplois-non-artistiques"
|
|
tabIndex={-1}
|
|
>
|
|
Emplois non artistiques
|
|
</button>
|
|
</div>
|
|
|
|
{/* Panneaux */}
|
|
<div id="ccneac-artistes-dramatiques" className="ccneac-panel active" role="tabpanel">
|
|
<ArtistesDramatiquesContent />
|
|
</div>
|
|
<div id="ccneac-artistes-musiciens" className="ccneac-panel" role="tabpanel" hidden>
|
|
<ArtistesMusiciensContent />
|
|
</div>
|
|
<div id="ccneac-artistes-lyriques" className="ccneac-panel" role="tabpanel" hidden>
|
|
<ArtistesLyriquesContent />
|
|
</div>
|
|
<div id="ccneac-artistes-cirque" className="ccneac-panel" role="tabpanel" hidden>
|
|
<ArtistesCirqueContent />
|
|
</div>
|
|
<div id="ccneac-emplois-non-artistiques" className="ccneac-panel" role="tabpanel" hidden>
|
|
<EmploisNonArtistiquesContent />
|
|
</div>
|
|
</section>
|
|
|
|
{/* Bouton flottant Simulateur */}
|
|
<button
|
|
onClick={() => setIsSimulateurOpen(!isSimulateurOpen)}
|
|
className="fixed bottom-6 right-6 z-50 inline-flex items-center gap-2 px-5 py-3 rounded-full text-sm font-bold bg-gradient-to-r from-amber-400 to-amber-500 text-slate-900 hover:from-amber-500 hover:to-amber-600 transition-all shadow-lg hover:shadow-xl hover:scale-105"
|
|
>
|
|
<Calculator className="w-5 h-5" />
|
|
Simulateur
|
|
</button>
|
|
|
|
{/* Modale compacte qui sort du bouton */}
|
|
{isSimulateurOpen && (
|
|
<>
|
|
{/* Modale compacte déplaçable */}
|
|
<div
|
|
ref={modalRef}
|
|
className="fixed z-50 w-[500px] max-h-[680px] bg-white rounded-2xl shadow-2xl flex flex-col overflow-hidden"
|
|
style={{
|
|
left: modalPosition.x !== 0 ? `${modalPosition.x}px` : 'auto',
|
|
top: modalPosition.y !== 0 ? `${modalPosition.y}px` : 'auto',
|
|
bottom: modalPosition.x === 0 && modalPosition.y === 0 ? '6rem' : 'auto',
|
|
right: modalPosition.x === 0 && modalPosition.y === 0 ? '1.5rem' : 'auto',
|
|
}}
|
|
>
|
|
{/* Header draggable */}
|
|
<div
|
|
className="flex items-center justify-between px-4 py-3 border-b bg-gradient-to-r from-amber-50 to-orange-50 cursor-move select-none touch-none"
|
|
onPointerDown={onPointerDown}
|
|
onPointerMove={onPointerMove}
|
|
onPointerUp={onPointerUp}
|
|
>
|
|
<h3 className="text-sm font-bold text-slate-900 flex items-center gap-2">
|
|
<Calculator className="w-4 h-4 text-amber-600" />
|
|
Simulateur de paie
|
|
</h3>
|
|
<button
|
|
onClick={() => {
|
|
setIsSimulateurOpen(false);
|
|
setModalPosition({ x: 0, y: 0 }); // Réinitialiser la position
|
|
}}
|
|
className="p-1.5 rounded-lg hover:bg-slate-100 transition-colors"
|
|
aria-label="Fermer le simulateur"
|
|
onPointerDown={(e) => e.stopPropagation()}
|
|
>
|
|
<X className="w-4 h-4 text-slate-600" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Content avec scroll */}
|
|
<div className="flex-1 overflow-auto p-4">
|
|
<SimulateurContent hideInfoPanel />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* Calculatrice globale */}
|
|
<CalculatorComponent
|
|
isOpen={isCalculatorOpen}
|
|
onClose={() => setIsCalculatorOpen(false)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|