espace-paie-odentas/app/(app)/minima-ccn/ccnsvp/page.tsx

573 lines
17 KiB
TypeScript

"use client";
import React, { useEffect } from 'react';
import { usePageTitle } from '@/hooks/usePageTitle';
import Link from 'next/link';
import { ArrowLeft, Scale, Calculator } from 'lucide-react';
import Annexe1Content from './annexe1-data';
import ClausesCommunesContent from './clauses-communes-data';
import Annexe2Content from './annexe2-data';
import Annexe3Content from './annexe3-data';
import Annexe4Content from './annexe4-data';
import Annexe5Content from './annexe5-data';
export default function CCNSVPPage() {
usePageTitle("Minima CCNSVP");
useEffect(() => {
// Script de gestion des onglets
const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
const panels = Array.from(document.querySelectorAll('.ccnsvp-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>{`
.ccnsvp-tabs [role="tablist"] {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 20px;
}
.ccnsvp-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;
position: relative;
}
.ccnsvp-tabs [role="tab"]:hover {
background: #f8fafc;
border-color: #cbd5e1;
}
.ccnsvp-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);
}
.ccnsvp-tabs [role="tab"]:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
/* Tooltips */
.ccnsvp-tabs [role="tab"][data-tip]::after {
content: attr(data-tip);
position: absolute;
left: 50%;
transform: translateX(-50%);
top: calc(100% + 8px);
background: #0f172a;
color: white;
padding: 8px 12px;
border-radius: 8px;
font-size: 12px;
line-height: 1.4;
white-space: normal;
max-width: min(72vw, 340px);
opacity: 0;
pointer-events: none;
z-index: 50;
transition: opacity 0.2s;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.ccnsvp-tabs [role="tab"][data-tip]::before {
content: "";
position: absolute;
left: 50%;
transform: translateX(-50%);
top: calc(100% + 4px);
border: 6px solid transparent;
border-bottom-color: #0f172a;
opacity: 0;
z-index: 50;
transition: opacity 0.2s;
}
.ccnsvp-tabs [role="tab"][data-tip]:hover::after,
.ccnsvp-tabs [role="tab"][data-tip]:hover::before,
.ccnsvp-tabs [role="tab"][data-tip]:focus-visible::after,
.ccnsvp-tabs [role="tab"][data-tip]:focus-visible::before {
opacity: 1;
}
.ccnsvp-panel {
display: none;
}
.ccnsvp-panel.active {
display: block;
}
/* Alertes */
.ccnsvp-alert {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 12px 16px;
border-radius: 12px;
border: 1px solid #fed7aa;
background: #fff7ed;
color: #9a3412;
font-size: 13px;
line-height: 1.5;
margin-top: 12px;
}
.ccnsvp-alert .icon {
font-size: 18px;
flex-shrink: 0;
}
/* Tables */
.ccnsvp-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 14px;
}
.ccnsvp-table th,
.ccnsvp-table td {
border-top: 1px solid #e2e8f0;
padding: 12px;
text-align: left;
vertical-align: top;
}
.ccnsvp-table th {
background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
font-weight: 700;
color: #475569;
border-top-color: #c7d2fe;
}
.ccnsvp-table tbody tr:first-child td {
border-top: 0;
}
.ccnsvp-table tbody tr:hover {
background: #f8fafc;
}
/* KPIs */
.ccnsvp-kpi {
background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
border: 1px solid #c7d2fe;
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
}
.ccnsvp-kpi .lbl {
font-weight: 700;
font-size: 14px;
color: #64748b;
margin: 0 0 6px 0;
}
.ccnsvp-kpi .num {
font-size: 24px;
font-weight: 900;
color: #1e293b;
margin-bottom: 4px;
}
.ccnsvp-kpi .muted {
color: #64748b;
font-size: 13px;
line-height: 1.5;
}
/* Recherche */
.ccnsvp-search {
display: flex;
gap: 12px;
align-items: center;
margin: 16px 0;
}
.ccnsvp-search input {
flex: 1;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 12px 16px;
font-size: 14px;
}
.ccnsvp-search input:focus {
outline: 2px solid #6366f1;
outline-offset: 0;
border-color: #6366f1;
}
.ccnsvp-badge {
display: inline-block;
background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
border: 1px solid #c7d2fe;
border-radius: 999px;
padding: 6px 12px;
font-size: 12px;
font-weight: 700;
color: #4f46e5;
}
/* Accordéons */
.ccnsvp-acc details {
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 12px 16px;
background: white;
margin-bottom: 8px;
}
.ccnsvp-acc summary {
cursor: pointer;
font-weight: 700;
color: #1e293b;
outline: none;
list-style: none;
}
.ccnsvp-acc summary::-webkit-details-marker {
display: none;
}
.ccnsvp-acc ul {
list-style: none;
padding: 0;
margin: 12px 0 0;
}
.ccnsvp-acc li {
padding: 10px 0;
border-top: 1px solid #e2e8f0;
cursor: pointer;
transition: color 0.2s;
}
.ccnsvp-acc li:first-child {
border-top: 0;
}
.ccnsvp-acc li:hover {
color: #6366f1;
}
/* Highlight animation */
.hl {
animation: flash 2s ease;
}
@keyframes flash {
0% { background: #fff7ed; }
100% { background: transparent; }
}
/* Grille responsive */
.ccnsvp-grid {
display: grid;
gap: 20px;
}
@media (min-width: 900px) {
.ccnsvp-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
/* KPI blocks */
.kpi-blocks {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 12px;
margin-top: 12px;
}
.kpi-block {
background: white;
border: 1px solid #e2e8f0;
border-radius: 10px;
padding: 12px;
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
}
.kpi-block-label {
font-weight: 700;
font-size: 14px;
color: #475569;
}
.kpi-block-num {
font-weight: 900;
font-size: 18px;
color: #1e293b;
white-space: nowrap;
}
`}</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-blue-500 to-cyan-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">CCNSVP (IDCC 3090)</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">
Spectacle vivant privé - Minima techniciens, artistes et personnels administratifs et commerciaux
</p>
<p className="text-xs text-slate-500">
Données issues de l'accord sur les salaires signé le 25/01/2024, entré en vigueur le 01/02/2024, étendu par arrêté ministériel du 25/03/2024.
<br />
Toujours en vigueur au 2e semestre 2025. <strong>Tous les montants sont exprimés bruts.</strong>
</p>
<div className="ccnsvp-alert mt-3">
<span className="icon" aria-hidden="true">⚠️</span>
<span>
Les <b>metteurs en scène</b> ne sont pas prévus par la CCNSVP ;
il convient donc d'appliquer au minimum le <b>SMIC</b> (taux horaire de 11,88 brut à ce jour).
</span>
</div>
</div>
</div>
</section>
{/* Onglets */}
<section className="rounded-2xl border bg-white p-6 ccnsvp-tabs">
<div className="flex items-center justify-between mb-4">
<p className="text-sm text-slate-600">
Survolez le nom d'une annexe pour connaître son titre exact, cliquez sur l'annexe pour accéder aux détails.
</p>
<Link
href="/simulateur"
className="inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-semibold bg-gradient-to-r from-amber-400 to-amber-500 text-slate-900 hover:from-amber-500 hover:to-amber-600 transition-all shadow-sm"
>
<Calculator className="w-4 h-4" />
Simulateur
</Link>
</div>
<div role="tablist" aria-label="Onglets CCNSVP">
<button
role="tab"
aria-selected="true"
aria-controls="ccnsvp-communes"
tabIndex={0}
data-tip="Grilles de salaires des emplois administratifs et commerciaux, et des emplois techniques hors annexe"
>
Clauses communes
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a1"
tabIndex={-1}
data-tip="Annexe 1 — Exploitants de lieux, producteurs ou diffuseurs de spectacles dramatiques, lyriques, chorégraphiques et de musique classique"
>
Annexe 1
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a2"
tabIndex={-1}
data-tip="Annexe 2 — Exploitants de lieux, producteurs ou diffuseurs de spectacles de chanson, variétés, jazz, musiques actuelles"
>
Annexe 2
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a3"
tabIndex={-1}
data-tip="Exploitants de lieux, producteurs ou diffuseurs de spectacles de cabarets"
>
Annexe 3
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a4"
tabIndex={-1}
data-tip="Producteurs ou diffuseurs de spectacles en tournée (à l'exception des cirques et des bals)"
>
Annexe 4
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a5"
tabIndex={-1}
data-tip="Producteurs ou diffuseurs de spectacles de cirque"
>
Annexe 5
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-a6"
tabIndex={-1}
data-tip="Producteurs, diffuseurs, organisateurs occasionnels (y compris les particuliers) de spectacles de bals avec ou sans orchestre"
>
Annexe 6
</button>
<button
role="tab"
aria-selected="false"
aria-controls="ccnsvp-indem"
tabIndex={-1}
>
Indemnités
</button>
</div>
{/* Panneaux */}
<div id="ccnsvp-communes" className="ccnsvp-panel active" role="tabpanel">
<ClausesCommunesContent />
</div>
<div id="ccnsvp-a1" className="ccnsvp-panel" role="tabpanel" hidden>
<Annexe1Content />
</div>
<div id="ccnsvp-a2" className="ccnsvp-panel" role="tabpanel" hidden>
<Annexe2Content />
</div>
<div id="ccnsvp-a3" className="ccnsvp-panel" role="tabpanel" hidden>
<Annexe3Content />
</div>
<div id="ccnsvp-a4" className="ccnsvp-panel" role="tabpanel" hidden>
<Annexe4Content />
</div>
<div id="ccnsvp-a5" className="ccnsvp-panel" role="tabpanel" hidden>
<Annexe5Content />
</div>
<div id="ccnsvp-a6" className="ccnsvp-panel" role="tabpanel" hidden>
<div className="text-center py-12">
<p className="text-slate-500">Contenu de l'Annexe 6 (Bals avec ou sans orchestre) à venir</p>
</div>
</div>
<div id="ccnsvp-indem" className="ccnsvp-panel" role="tabpanel" hidden>
<div className="text-center py-12">
<p className="text-slate-500">Contenu des indemnités à venir</p>
</div>
</div>
</section>
{/* Note informative */}
<section className="rounded-xl border border-blue-200 bg-blue-50 p-4">
<div className="flex items-start gap-3">
<div className="flex-shrink-0">
<div className="w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center">
<svg
className="w-5 h-5 text-blue-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
</div>
<div className="flex-1 min-w-0">
<h3 className="text-sm font-semibold text-blue-900 mb-1">
Minima conventionnels
</h3>
<p className="text-sm text-blue-800">
Les minima affichés sont issus de la convention collective nationale CCNSVP et sont mis à jour régulièrement.
Ils constituent une base de référence pour l'établissement des contrats de travail.
Les tableaux détaillés par annexe seront progressivement intégrés.
</p>
</div>
</div>
</section>
</div>
);
}