- Créer hook useStaffOrgSelection avec persistence localStorage - Ajouter badge StaffOrgBadge dans Sidebar - Synchroniser filtres org dans toutes les pages (contrats, cotisations, facturation, etc.) - Fix calcul cachets: utiliser totalQuantities au lieu de dates.length - Fix structure field bug: ne plus écraser avec production_name - Ajouter création note lors modification contrat - Implémenter montants personnalisés pour virements salaires - Migrations SQL: custom_amount + fix_structure_field - Réorganiser boutons ContractEditor en carte flottante droite
640 lines
23 KiB
TypeScript
640 lines
23 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useSearchParams, useRouter } from "next/navigation";
|
|
import { useDebouncedCallback } from "use-debounce";
|
|
import { useQuery, keepPreviousData } from "@tanstack/react-query";
|
|
import { useMemo, useState, useEffect } from "react";
|
|
import { api } from "@/lib/fetcher";
|
|
import { Loader2, ChevronLeft, ChevronRight, Plus } from "lucide-react";
|
|
import { usePageTitle } from "@/hooks/usePageTitle";
|
|
import { useDemoMode } from "@/hooks/useDemoMode";
|
|
import { useStaffOrgSelection } from "@/hooks/useStaffOrgSelection";
|
|
|
|
/* ===== Types ===== */
|
|
type SalarieRow = {
|
|
matricule: string; // "Code salarié"
|
|
nom: string;
|
|
email?: string | null;
|
|
transat_connecte?: boolean;
|
|
dernier_emploi?: string | null;
|
|
dernier_contrat?: {
|
|
id: string;
|
|
reference: string;
|
|
is_multi_mois?: boolean;
|
|
regime?: "CDDU_MONO" | "CDDU_MULTI" | "RG" | string;
|
|
} | null;
|
|
};
|
|
|
|
type SalariesResponse = {
|
|
items: SalarieRow[];
|
|
page: number;
|
|
limit: number;
|
|
total?: number;
|
|
totalPages?: number;
|
|
hasMore: boolean;
|
|
};
|
|
|
|
type ClientInfo = {
|
|
id: string;
|
|
name: string;
|
|
api_name?: string;
|
|
} | null;
|
|
|
|
/* ===== Helpers ===== */
|
|
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
|
return (
|
|
<section className="rounded-2xl border bg-white">
|
|
<div className="px-4 py-3 border-b font-medium text-slate-700 bg-slate-50/60">
|
|
{title}
|
|
</div>
|
|
<div className="p-4">{children}</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function lastContractHref(c?: SalarieRow["dernier_contrat"]) {
|
|
if (!c) return null;
|
|
const isMulti = c.is_multi_mois === true || (c.regime && c.regime.toUpperCase() === "CDDU_MULTI");
|
|
return isMulti ? `/contrats-multi/${c.id}` : `/contrats/${c.id}`;
|
|
}
|
|
|
|
/* ===== Composant de pagination ===== */
|
|
type PaginationProps = {
|
|
page: number;
|
|
totalPages: number;
|
|
total: number;
|
|
limit: number;
|
|
onPageChange: (page: number) => void;
|
|
onLimitChange: (limit: number) => void;
|
|
isFetching?: boolean;
|
|
itemsCount: number;
|
|
position?: 'top' | 'bottom';
|
|
};
|
|
|
|
function Pagination({ page, totalPages, total, limit, onPageChange, onLimitChange, isFetching, itemsCount, position = 'bottom' }: PaginationProps) {
|
|
return (
|
|
<div className={`p-3 flex flex-col sm:flex-row items-center gap-3 ${position === 'bottom' ? 'border-t' : ''}`}>
|
|
{/* Navigation */}
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={() => onPageChange(Math.max(1, page - 1))}
|
|
disabled={page === 1}
|
|
className="px-2 py-1 rounded-lg border disabled:opacity-40 hover:bg-slate-50 disabled:hover:bg-transparent"
|
|
>
|
|
<ChevronLeft className="w-4 h-4"/>
|
|
</button>
|
|
<div className="text-sm">
|
|
Page <strong>{page}</strong> sur <strong>{totalPages || 1}</strong>
|
|
</div>
|
|
<button
|
|
onClick={() => onPageChange(page + 1)}
|
|
disabled={page >= totalPages}
|
|
className="px-2 py-1 rounded-lg border disabled:opacity-40 hover:bg-slate-50 disabled:hover:bg-transparent"
|
|
>
|
|
<ChevronRight className="w-4 h-4"/>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Sélecteur de limite */}
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<span className="text-slate-600">Afficher :</span>
|
|
<select
|
|
value={limit}
|
|
onChange={(e) => onLimitChange(parseInt(e.target.value, 10))}
|
|
className="px-2 py-1 rounded-lg border bg-white text-sm"
|
|
>
|
|
<option value={10}>10</option>
|
|
<option value={50}>50</option>
|
|
<option value={100}>100</option>
|
|
</select>
|
|
</div>
|
|
|
|
{/* Informations */}
|
|
<div className="sm:ml-auto text-sm text-slate-600">
|
|
{isFetching ? (
|
|
<span className="flex items-center gap-1">
|
|
<Loader2 className="w-3 h-3 animate-spin" />
|
|
Mise à jour…
|
|
</span>
|
|
) : (
|
|
<span>
|
|
{total > 0 ? (
|
|
<>
|
|
<strong>{total}</strong> salarié{total > 1 ? 's' : ''} au total
|
|
{itemsCount > 0 && ` • ${itemsCount} affiché${itemsCount > 1 ? 's' : ''}`}
|
|
</>
|
|
) : (
|
|
'Aucun salarié'
|
|
)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/* ===== Data hook ===== */
|
|
function useSalaries(page: number, limit: number, search: string, org?: string | null, isDemoMode: boolean = false) {
|
|
|
|
console.log('🔍 useSalaries debug:', {
|
|
isDemoMode,
|
|
page,
|
|
search
|
|
});
|
|
|
|
// 🎭 Mode démo : utiliser les données fictives DIRECTEMENT
|
|
if (isDemoMode) {
|
|
console.log('🎭 Demo mode detected, loading demo salaries...');
|
|
|
|
// Données fictives de salariés
|
|
const DEMO_SALARIES: SalarieRow[] = [
|
|
{
|
|
matricule: "demo-sal-001",
|
|
nom: "MARTIN Alice",
|
|
email: "alice.martin@demo.fr",
|
|
transat_connecte: true,
|
|
dernier_emploi: "Comédien",
|
|
dernier_contrat: {
|
|
id: "demo-cont-001",
|
|
reference: "DEMO-2024-001",
|
|
is_multi_mois: true,
|
|
regime: "CDDU_MULTI"
|
|
}
|
|
},
|
|
{
|
|
matricule: "demo-sal-002",
|
|
nom: "DUBOIS Pierre",
|
|
email: "pierre.dubois@demo.fr",
|
|
transat_connecte: false,
|
|
dernier_emploi: "Metteur en scène",
|
|
dernier_contrat: {
|
|
id: "demo-cont-002",
|
|
reference: "DEMO-2024-002",
|
|
is_multi_mois: false,
|
|
regime: "CDDU_MONO"
|
|
}
|
|
},
|
|
{
|
|
matricule: "demo-sal-003",
|
|
nom: "LEROY Sophie",
|
|
email: "sophie.leroy@demo.fr",
|
|
transat_connecte: true,
|
|
dernier_emploi: "Danseur",
|
|
dernier_contrat: {
|
|
id: "demo-cont-003",
|
|
reference: "DEMO-2024-003",
|
|
is_multi_mois: true,
|
|
regime: "CDDU_MULTI"
|
|
}
|
|
},
|
|
{
|
|
matricule: "demo-sal-004",
|
|
nom: "BERNARD Marc",
|
|
email: "marc.bernard@demo.fr",
|
|
transat_connecte: false,
|
|
dernier_emploi: "Technicien son",
|
|
dernier_contrat: {
|
|
id: "demo-cont-004",
|
|
reference: "DEMO-2024-004",
|
|
is_multi_mois: false,
|
|
regime: "CDDU_MONO"
|
|
}
|
|
},
|
|
{
|
|
matricule: "demo-sal-005",
|
|
nom: "GARCIA Elena",
|
|
email: "elena.garcia@demo.fr",
|
|
transat_connecte: true,
|
|
dernier_emploi: "Costumière",
|
|
dernier_contrat: {
|
|
id: "demo-cont-005",
|
|
reference: "DEMO-2024-005",
|
|
is_multi_mois: true,
|
|
regime: "CDDU_MULTI"
|
|
}
|
|
}
|
|
];
|
|
|
|
// Filtrer par recherche si nécessaire
|
|
const filteredSalaries = DEMO_SALARIES.filter(salarie => {
|
|
if (search.trim()) {
|
|
const searchTerm = search.toLowerCase();
|
|
return salarie.nom.toLowerCase().includes(searchTerm) ||
|
|
salarie.matricule.toLowerCase().includes(searchTerm) ||
|
|
salarie.email?.toLowerCase().includes(searchTerm) ||
|
|
salarie.dernier_emploi?.toLowerCase().includes(searchTerm);
|
|
}
|
|
return true;
|
|
});
|
|
|
|
// Pagination simple
|
|
const startIndex = (page - 1) * limit;
|
|
const endIndex = startIndex + limit;
|
|
const paginatedSalaries = filteredSalaries.slice(startIndex, endIndex);
|
|
|
|
console.log('✅ Filtered demo salaries:', filteredSalaries.length, 'total,', paginatedSalaries.length, 'on page', page);
|
|
|
|
return {
|
|
data: {
|
|
items: paginatedSalaries,
|
|
page,
|
|
limit,
|
|
total: filteredSalaries.length,
|
|
totalPages: Math.ceil(filteredSalaries.length / limit),
|
|
hasMore: endIndex < filteredSalaries.length,
|
|
},
|
|
isLoading: false,
|
|
error: null,
|
|
isError: false,
|
|
isFetching: false
|
|
};
|
|
}
|
|
|
|
// Mode normal : récupération via API
|
|
// Récupération dynamique des infos client via /api/me
|
|
const { data: clientInfo } = useQuery({
|
|
queryKey: ["client-info"],
|
|
queryFn: async () => {
|
|
try {
|
|
const res = await fetch("/api/me", {
|
|
cache: "no-store",
|
|
headers: { Accept: "application/json" },
|
|
credentials: "include"
|
|
});
|
|
if (!res.ok) return null;
|
|
const me = await res.json();
|
|
|
|
return {
|
|
id: me.active_org_id || null,
|
|
name: me.active_org_name || "Organisation",
|
|
api_name: me.active_org_api_name
|
|
} as ClientInfo;
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
staleTime: 30_000, // Cache 30s
|
|
});
|
|
|
|
const params = new URLSearchParams();
|
|
params.set("page", String(page));
|
|
params.set("limit", String(limit));
|
|
if (search.trim()) params.set("search", search.trim());
|
|
|
|
// We'll return a tuple: a query function that accepts an optional org override
|
|
return useQuery<SalariesResponse>({
|
|
queryKey: ["salaries", page, limit, search, clientInfo?.id, org],
|
|
queryFn: () => {
|
|
// If an explicit org override is provided (staff filtering), pass it via clientInfo override
|
|
const finalClientInfo = clientInfo ? { ...clientInfo, id: org ?? clientInfo.id } : (org ? { id: org, name: "Organisation", api_name: undefined } as ClientInfo : null);
|
|
return api<SalariesResponse>(`/salaries?${params.toString()}`, {}, finalClientInfo);
|
|
},
|
|
staleTime: 10_000,
|
|
gcTime: 5 * 60 * 1000,
|
|
placeholderData: keepPreviousData,
|
|
initialData: undefined,
|
|
enabled: !!clientInfo,
|
|
});
|
|
}
|
|
|
|
/* ===== Page ===== */
|
|
export default function SalariesPage() {
|
|
usePageTitle("Salariés");
|
|
|
|
// 🎭 Détection du mode démo
|
|
const { isDemoMode } = useDemoMode();
|
|
|
|
// Helper pour valider les UUIDs
|
|
const isValidUUID = (str: string | null): boolean => {
|
|
if (!str) return false;
|
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
};
|
|
|
|
// Zustand store pour la sélection d'organisation (staff)
|
|
const {
|
|
selectedOrgId: globalSelectedOrgId,
|
|
setSelectedOrg: setGlobalSelectedOrg
|
|
} = useStaffOrgSelection();
|
|
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
|
|
const initialPage = Number(searchParams.get("page") || 1);
|
|
const initialSearch = searchParams.get("q") || "";
|
|
const [page, setPage] = useState(initialPage);
|
|
const [limit, setLimit] = useState(10);
|
|
const [query, setQuery] = useState(initialSearch);
|
|
|
|
const debouncedSearch = useDebouncedCallback((v: string) => {
|
|
setPage(1);
|
|
const sp = new URLSearchParams(searchParams.toString());
|
|
if (v.trim()) sp.set("q", v.trim()); else sp.delete("q");
|
|
sp.set("page", "1");
|
|
router.replace(`/salaries?${sp.toString()}`);
|
|
}, 300);
|
|
|
|
// (moved below, after selectedOrg declaration)
|
|
|
|
// Fetch /api/me and organizations for staff filter
|
|
const { data: meData } = useQuery({
|
|
queryKey: ["me-info"],
|
|
queryFn: async () => {
|
|
try {
|
|
const res = await fetch('/api/me', { cache: 'no-store', credentials: 'include' });
|
|
if (!res.ok) return null;
|
|
return await res.json();
|
|
} catch { return null; }
|
|
},
|
|
});
|
|
|
|
const [orgs, setOrgs] = useState<Array<{ id: string; name: string }>>([]);
|
|
// État local initialisé avec la valeur globale si elle est un UUID valide
|
|
const [selectedOrg, setSelectedOrg] = useState<string | null>(
|
|
isValidUUID(globalSelectedOrgId) ? globalSelectedOrgId : null
|
|
);
|
|
|
|
const { data, isLoading, isFetching } = useSalaries(page, limit, query, selectedOrg, isDemoMode);
|
|
const rows: SalarieRow[] = data?.items ?? [];
|
|
const hasMore: boolean = data?.hasMore ?? false;
|
|
const total = data?.total ?? 0;
|
|
const totalPages = data?.totalPages ?? 0;
|
|
|
|
useEffect(() => {
|
|
let mounted = true;
|
|
(async () => {
|
|
try {
|
|
const r = await fetch('/api/organizations', { cache: 'no-store', credentials: 'include' });
|
|
if (!r.ok) return;
|
|
const json = await r.json();
|
|
if (!mounted) return;
|
|
const items = (json && json.items) ? json.items : (Array.isArray(json) ? json : []);
|
|
setOrgs((items || []).map((o: any) => ({ id: o.id, name: o.name })));
|
|
} catch {}
|
|
})();
|
|
return () => { mounted = false; };
|
|
}, []);
|
|
|
|
// Synchronisation bidirectionnelle : global → local
|
|
useEffect(() => {
|
|
if (meData?.is_staff && isValidUUID(globalSelectedOrgId)) {
|
|
setSelectedOrg(globalSelectedOrgId);
|
|
}
|
|
}, [globalSelectedOrgId, meData?.is_staff]);
|
|
|
|
// Modal "Nouveau contrat" déclenché depuis la liste
|
|
const [newContratOpen, setNewContratOpen] = useState(false);
|
|
const [selectedMatricule, setSelectedMatricule] = useState<string | null>(null);
|
|
const [selectedNom, setSelectedNom] = useState<string | null>(null);
|
|
|
|
return (
|
|
<div className="space-y-5">
|
|
{/* Barre de titre + actions */}
|
|
<div className="rounded-2xl border bg-white p-4">
|
|
<div className="flex flex-col md:flex-row md:items-center gap-3">
|
|
<div className="text-lg font-semibold">Vos salariés</div>
|
|
<div className="md:ml-auto w-full md:w-auto">
|
|
<input
|
|
type="search"
|
|
placeholder="Rechercher (nom, email, matricule)…"
|
|
value={query}
|
|
onChange={(e) => {
|
|
const v = e.target.value;
|
|
setQuery(v);
|
|
debouncedSearch(v);
|
|
}}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") {
|
|
const v = (e.target as HTMLInputElement).value;
|
|
setQuery(v);
|
|
setPage(1);
|
|
const sp = new URLSearchParams(searchParams.toString());
|
|
if (v.trim()) sp.set("q", v.trim()); else sp.delete("q");
|
|
sp.set("page", "1");
|
|
router.replace(`/salaries?${sp.toString()}`);
|
|
}
|
|
}}
|
|
className="w-full md:w-80 px-3 py-2 rounded-lg border bg-white text-sm"
|
|
/>
|
|
</div>
|
|
{/* Organization filter for staff */}
|
|
{meData?.is_staff && (
|
|
<select
|
|
value={selectedOrg || ""}
|
|
onChange={(e) => {
|
|
const newOrgId = e.target.value || null;
|
|
setSelectedOrg(newOrgId);
|
|
setPage(1);
|
|
|
|
// Synchronisation bidirectionnelle : local → global
|
|
if (newOrgId) {
|
|
const selectedOrgData = orgs.find(o => o.id === newOrgId);
|
|
if (selectedOrgData) {
|
|
setGlobalSelectedOrg(newOrgId, selectedOrgData.name);
|
|
}
|
|
} else {
|
|
setGlobalSelectedOrg(null, null);
|
|
}
|
|
}}
|
|
className="ml-3 px-3 py-2 rounded-lg border bg-white text-sm"
|
|
>
|
|
<option value="">Toutes les structures</option>
|
|
{orgs.map(o => <option key={o.id} value={o.id}>{o.name}</option>)}
|
|
</select>
|
|
)}
|
|
<Link
|
|
href="/salaries/nouveau"
|
|
className="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-emerald-600 text-white hover:bg-emerald-700"
|
|
>
|
|
<Plus className="w-4 h-4" /> Nouveau salarié
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Pagination supérieure */}
|
|
{rows.length > 0 && (
|
|
<section className="rounded-2xl border bg-white">
|
|
<Pagination
|
|
page={page}
|
|
totalPages={totalPages}
|
|
total={total}
|
|
limit={limit}
|
|
onPageChange={(newPage) => setPage(newPage)}
|
|
onLimitChange={(newLimit) => { setLimit(newLimit); setPage(1); }}
|
|
isFetching={isFetching}
|
|
itemsCount={rows.length}
|
|
position="top"
|
|
/>
|
|
</section>
|
|
)}
|
|
|
|
{/* Tableau */}
|
|
<section className="rounded-2xl border bg-white">
|
|
<div className="px-4 py-3 border-b font-medium text-slate-700 bg-slate-50/60">
|
|
Liste
|
|
</div>
|
|
{isLoading ? (
|
|
<div className="p-4 py-10 text-center text-slate-500">
|
|
<Loader2 className="w-4 h-4 inline animate-spin mr-2" />
|
|
Chargement des salarié·e·s…
|
|
</div>
|
|
) : (
|
|
<>
|
|
<div className="p-4 overflow-x-auto">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="border-b bg-slate-50/80">
|
|
<th className="text-left font-medium px-3 py-2">Salarié</th>
|
|
<th className="text-left font-medium px-3 py-2 hidden md:table-cell">Structure</th>
|
|
<th className="text-left font-medium px-3 py-2">Matricule</th>
|
|
<th className="text-left font-medium px-3 py-2">Espace Transat</th>
|
|
<th className="text-left font-medium px-3 py-2">Adresse mail</th>
|
|
<th className="text-left font-medium px-3 py-2">Dernier emploi</th>
|
|
<th className="text-left font-medium px-3 py-2">Dernier contrat</th>
|
|
<th className="text-right font-medium px-3 py-2 pr-4">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{rows.length === 0 ? (
|
|
<tr>
|
|
<td colSpan={7} className="px-3 py-8 text-center text-slate-500">
|
|
Aucun résultat.
|
|
</td>
|
|
</tr>
|
|
) : (
|
|
rows.map((r: SalarieRow) => {
|
|
const contratHref = lastContractHref(r.dernier_contrat);
|
|
// 🎭 En mode démo, rediriger vers la page demo unique
|
|
const salarieHref = isDemoMode ? '/salaries/demo' : `/salaries/${r.matricule}`;
|
|
const contratHrefFinal = isDemoMode ? '/contrats/demo' : contratHref;
|
|
|
|
return (
|
|
<tr key={r.matricule} className="border-b last:border-0">
|
|
<td className="px-3 py-2">
|
|
<Link href={salarieHref} className="underline font-medium">
|
|
{r.nom}
|
|
</Link>
|
|
</td>
|
|
<td className="px-3 py-2 hidden md:table-cell">{(r as any).org_name || ''}</td>
|
|
<td className="px-3 py-2">{r.matricule}</td>
|
|
<td className="px-3 py-2">
|
|
<span className={`px-2 py-1 rounded-full text-xs whitespace-nowrap ${
|
|
r.transat_connecte ? "bg-emerald-100 text-emerald-800"
|
|
: "bg-rose-100 text-rose-800"
|
|
}`}>
|
|
{r.transat_connecte ? "Connecté" : "Non connecté"}
|
|
</span>
|
|
</td>
|
|
<td className="px-3 py-2">{r.email || <span className="text-slate-400">—</span>}</td>
|
|
<td className="px-3 py-2">{r.dernier_emploi || <span className="text-slate-400">—</span>}</td>
|
|
<td className="px-3 py-2">
|
|
{r.dernier_contrat && contratHrefFinal ? (
|
|
<Link href={contratHrefFinal} className="underline">{r.dernier_contrat.reference}</Link>
|
|
) : (
|
|
<span className="text-slate-400">—</span>
|
|
)}
|
|
</td>
|
|
<td className="px-3 py-2 text-right pr-4">
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedMatricule(r.matricule);
|
|
setSelectedNom(r.nom || r.matricule);
|
|
setNewContratOpen(true);
|
|
}}
|
|
className="inline-flex items-center justify-center w-8 h-8 rounded-lg border hover:bg-slate-50"
|
|
aria-label="Créer un contrat pour ce salarié"
|
|
title="Créer un contrat"
|
|
>
|
|
<Plus className="w-4 h-4" />
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
);
|
|
})
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{/* Pagination inférieure dans la Section */}
|
|
<Pagination
|
|
page={page}
|
|
totalPages={totalPages}
|
|
total={total}
|
|
limit={limit}
|
|
onPageChange={(newPage) => setPage(newPage)}
|
|
onLimitChange={(newLimit) => { setLimit(newLimit); setPage(1); }}
|
|
isFetching={isFetching}
|
|
itemsCount={rows.length}
|
|
position="bottom"
|
|
/>
|
|
</>
|
|
)}
|
|
</section>
|
|
|
|
{newContratOpen && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
{/* Backdrop */}
|
|
<div
|
|
className="absolute inset-0 bg-black/50"
|
|
onClick={() => setNewContratOpen(false)}
|
|
/>
|
|
|
|
{/* Modal */}
|
|
<div className="relative z-10 w-full max-w-md rounded-2xl border bg-white p-5 shadow-xl">
|
|
<div className="text-base font-medium mb-1">Créer un nouveau contrat</div>
|
|
{selectedNom && (
|
|
<div className="text-sm text-slate-600 mb-1">
|
|
Pour: <span className="font-medium">{selectedNom}</span>
|
|
</div>
|
|
)}
|
|
<p className="text-sm text-slate-500 mb-4">
|
|
Pour quel type de contrat souhaitez-vous procéder ?
|
|
</p>
|
|
|
|
<div className="grid grid-cols-1 gap-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setNewContratOpen(false);
|
|
if (selectedMatricule) {
|
|
router.push(`/contrats/nouveau?salarie=${encodeURIComponent(selectedMatricule)}`);
|
|
}
|
|
}}
|
|
className="w-full px-3 py-2 rounded-lg border text-sm hover:bg-slate-50 text-left"
|
|
>
|
|
CDDU
|
|
<div className="text-xs text-slate-500">Contrat à durée déterminée d'usage</div>
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
// Non fonctionnel pour l'instant
|
|
setNewContratOpen(false);
|
|
}}
|
|
className="w-full px-3 py-2 rounded-lg border text-sm opacity-70 cursor-not-allowed text-left"
|
|
title="Bientôt disponible"
|
|
disabled
|
|
>
|
|
Régime général
|
|
<div className="text-xs text-slate-500">Bientôt disponible</div>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="mt-4 flex justify-end">
|
|
<button
|
|
type="button"
|
|
onClick={() => setNewContratOpen(false)}
|
|
className="text-sm px-3 py-2 rounded-lg border"
|
|
>
|
|
Annuler
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|