diff --git a/app/(app)/contrats/[id]/page.tsx b/app/(app)/contrats/[id]/page.tsx index de313b2..96dfc46 100644 --- a/app/(app)/contrats/[id]/page.tsx +++ b/app/(app)/contrats/[id]/page.tsx @@ -1222,9 +1222,9 @@ return ( {/* Grille 2 colonnes */} -
- {/* Left column: Documents, Demande */} -
+
+ {/* Left column: Documents, Demande - ordre 1 sur mobile */} +
{/* Card Documents */} - -
- {/* Right column: Signature électronique, Déclarations, Paie, Temps de travail réel */} -
+ {/* Right column: Signature électronique, Déclarations, Paie, Temps de travail réel - ordre 2 sur mobile */} +
{/* Card de signature électronique */} @@ -1468,6 +1466,11 @@ return (
+ + {/* Section Notes - ordre 3 sur mobile (en dernier) */} +
+ +
{/* Script DocuSeal */} diff --git a/app/(app)/contrats/page.tsx b/app/(app)/contrats/page.tsx index cc9ec86..3c47ab7 100644 --- a/app/(app)/contrats/page.tsx +++ b/app/(app)/contrats/page.tsx @@ -330,12 +330,12 @@ export default function PageContrats(){
{/* Onglets + action */} -
-
+
+
-
+
Saisie en tableau ); } return ( -
+
diff --git a/app/(app)/cotisations/page.tsx b/app/(app)/cotisations/page.tsx index 8751559..21ed076 100644 --- a/app/(app)/cotisations/page.tsx +++ b/app/(app)/cotisations/page.tsx @@ -573,7 +573,7 @@ export default function CotisationsMensuellesPage() {
- + @@ -593,9 +593,11 @@ export default function CotisationsMensuellesPage() { {/* Ligne Total */} {total && ( - @@ -615,7 +617,7 @@ export default function CotisationsMensuellesPage() { <> {items.map((row) => ( -
PériodePériode Total URSSAF France Travail Spectacle
- - Total + +
+ + Total +
{EURO.format(total.total)} {EURO.format(total.urssaf)}
+
diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx index 54f9e9c..cd31a9b 100644 --- a/app/(app)/layout.tsx +++ b/app/(app)/layout.tsx @@ -54,14 +54,14 @@ export default async function AppLayout({ children }: { children: ReactNode }) { {/* Demo Banner */} -
+
{/* Sidebar flush left */} {/* Main column (header + content) */} -
+
{/* Header aligned with content column */}
@@ -71,7 +71,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
{/* Main content area */} -
+
{children}
@@ -180,14 +180,14 @@ export default async function AppLayout({ children }: { children: ReactNode }) { }; return ( -
+
{/* Sidebar flush left */} {/* Main column (header + content) */} -
+
{/* Header aligned with content column */}
@@ -197,7 +197,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
{/* Main content area */} -
+
{children}
@@ -302,14 +302,14 @@ export default async function AppLayout({ children }: { children: ReactNode }) { const displayInfo = isStaff ? staffOrgInfo : clientInfo; return ( -
+
{/* Sidebar flush left */} {/* Main column (header + content) */} -
+
{/* Header aligned with content column */}
@@ -319,7 +319,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
{/* Main content area */} -
+
{children}
diff --git a/app/(app)/page.tsx b/app/(app)/page.tsx index 569edf0..13432af 100644 --- a/app/(app)/page.tsx +++ b/app/(app)/page.tsx @@ -147,26 +147,28 @@ export default function Dashboard() { ))} -
-
+
+
-
diff --git a/app/(app)/signatures-electroniques/page.tsx b/app/(app)/signatures-electroniques/page.tsx index 7b165a2..794dd17 100644 --- a/app/(app)/signatures-electroniques/page.tsx +++ b/app/(app)/signatures-electroniques/page.tsx @@ -763,29 +763,29 @@ export default function SignaturesElectroniques() {

{/* Statut de la signature */} -
+
{currentSignature ? ( <> -
+
Signature connue
) : ( <> -
+
Signature non connue
@@ -1046,7 +1046,7 @@ export default function SignaturesElectroniques() { {/* Affichage de la signature actuelle */} {currentSignature && (
-
+
@@ -1054,28 +1054,30 @@ export default function SignaturesElectroniques() { ) : ( -
- Confirmer ? - - +
+ Confirmer ? +
+ + +
)}
diff --git a/app/(app)/vos-acces/page.tsx b/app/(app)/vos-acces/page.tsx index a5b901e..193187d 100644 --- a/app/(app)/vos-acces/page.tsx +++ b/app/(app)/vos-acces/page.tsx @@ -204,13 +204,13 @@ export default function StaffUsersListPage() { return (
-
+

- Utilisateurs de la structure {clientInfo.name} + Utilisateurs de la structure {clientInfo.name}

+ Créer un utilisateur @@ -239,49 +239,50 @@ export default function StaffUsersListPage() {
- - - - - - - - - - - - - {members.length === 0 ? ( +
+
PrénomEmailNiveauCréé leStatutActions
+ - + + + + + + - ) : ( - sortedMembers.map((m) => { - const created = m.created_at ? new Date(m.created_at as string) : null; - const createdFmt = created - ? created.toLocaleString("fr-FR", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - }) - : "—"; - const status = m.revoked ? "Révoqué" : "Actif"; - const disabled = !!m.revoked; - const isSelf = - (currentUserId && m.user_id === currentUserId) || - (currentUserEmail && typeof m.email === "string" && m.email.toLowerCase() === currentUserEmail.toLowerCase()); - // console.debug("ROW SELF CHECK", { currentUserId, rowUserId: m.user_id, currentUserEmail, rowEmail: m.email, isSelf }); - return ( - - - - - - + + + {members.length === 0 ? ( + + + + ) : ( + sortedMembers.map((m) => { + const created = m.created_at ? new Date(m.created_at as string) : null; + const createdFmt = created + ? created.toLocaleString("fr-FR", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }) + : "—"; + const status = m.revoked ? "Révoqué" : "Actif"; + const disabled = !!m.revoked; + const isSelf = + (currentUserId && m.user_id === currentUserId) || + (currentUserEmail && typeof m.email === "string" && m.email.toLowerCase() === currentUserEmail.toLowerCase()); + // console.debug("ROW SELF CHECK", { currentUserId, rowUserId: m.user_id, currentUserEmail, rowEmail: m.email, isSelf }); + return ( + + + + + +
- Aucun utilisateur pour cette structure. - PrénomEmailNiveauCréé leStatutActions
{m.first_name || "—"}{m.email}{m.role || "—"}{createdFmt}{status}
+ Aucun utilisateur pour cette structure. +
{m.first_name || "—"}{m.email}{m.role || "—"}{createdFmt}{status} { m.role === "SUPER_ADMIN" ? ( @@ -341,6 +342,7 @@ export default function StaffUsersListPage() { )}
+
diff --git a/app/signin/page.tsx b/app/signin/page.tsx index 62faf11..5203667 100644 --- a/app/signin/page.tsx +++ b/app/signin/page.tsx @@ -538,7 +538,7 @@ export default function SignIn() {
@@ -554,7 +554,7 @@ export default function SignIn() { value={mfaDigits[i] || ""} onChange={(e) => handleMfaDigitChange(i, e.target.value)} onKeyDown={(e) => handleMfaKeyDown(i, e)} - className="w-12 h-12 text-center text-xl font-mono border-2 border-[#6366f1]/40 rounded-xl bg-white/30 text-[#171424] focus:outline-none focus:ring-2 focus:ring-[#6366f1] shadow-md transition" + className="flex-1 h-12 sm:h-14 text-center text-xl sm:text-2xl font-mono border-2 border-[#6366f1]/40 rounded-xl bg-white/30 text-[#171424] focus:outline-none focus:ring-2 focus:ring-[#6366f1] shadow-md transition" /> ))}
@@ -612,7 +612,7 @@ export default function SignIn() { {otpStep === "code" && (
@@ -628,7 +628,7 @@ export default function SignIn() { value={codeDigits[i] || ""} onChange={(e) => handleDigitChange(i, e.target.value)} onKeyDown={(e) => handleKeyDown(i, e)} - className="w-14 h-16 text-center text-3xl rounded-2xl bg-white/70 border-2 border-[#6366f1]/40 text-[#171424] placeholder-[#171424]/40 focus:outline-none focus:ring-2 focus:ring-[#6366f1]/40 shadow-lg transition" + className="w-12 sm:w-14 h-14 sm:h-16 text-center text-2xl sm:text-3xl rounded-xl sm:rounded-2xl bg-white/70 border-2 border-[#6366f1]/40 text-[#171424] placeholder-[#171424]/40 focus:outline-none focus:ring-2 focus:ring-[#6366f1]/40 shadow-lg transition" style={{ fontWeight: 700, letterSpacing: "0.1em" }} aria-label={`Chiffre ${i + 1}`} /> diff --git a/components/Header.tsx b/components/Header.tsx index e5b5915..d2195b2 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,5 +1,5 @@ "use client"; -import { Search } from "lucide-react"; +import { Search, Menu } from "lucide-react"; import * as React from "react"; import { Command } from "cmdk"; import StatusEditModal from "./StatusEditModal"; @@ -158,9 +158,7 @@ export default function Header({ clientInfo, isStaff }: { aria-label="Ouvrir le menu" onClick={() => window.dispatchEvent(new CustomEvent("open-mobile-sidebar"))} > - - - + (null); + const [isStaff, setIsStaff] = useState(false); - const close = useCallback(() => setOpen(false), []); + const close = useCallback(() => { + setClosing(true); + setTimeout(() => { + setOpen(false); + setClosing(false); + }, 180); // Durée de l'animation + }, []); + const openEvt = useCallback(() => setOpen(true), []); + // Récupérer les infos du client et le statut staff + useEffect(() => { + let cancelled = false; + async function fetchUserInfo() { + try { + const res = await fetch('/api/me', { credentials: 'include', cache: 'no-store' }); + if (!res.ok) throw new Error(String(res.status)); + const data = await res.json(); + if (!cancelled) { + // Transformer la réponse API en format clientInfo attendu par Sidebar + const clientInfo = { + id: data.active_org_id || '', + name: data.active_org_name || 'Organisation', + api_name: data.active_org_api_name || null, + user: data.user || null + }; + setClientInfo(clientInfo); + setIsStaff(data.is_staff || false); + } + } catch (err) { + console.error('Error fetching user info:', err); + } + } + fetchUserInfo(); + return () => { cancelled = true; }; + }, []); + useEffect(() => { const onOpen = () => openEvt(); const onClose = () => close(); @@ -23,9 +60,14 @@ export default function MobileSidebarOverlay({ clientInfo, isStaff }: { clientIn return (
-
+
@@ -40,6 +82,7 @@ export default function MobileSidebarOverlay({ clientInfo, isStaff }: { clientIn
); diff --git a/components/TicketTimeline.tsx b/components/TicketTimeline.tsx index 3669106..8558cff 100644 --- a/components/TicketTimeline.tsx +++ b/components/TicketTimeline.tsx @@ -49,8 +49,75 @@ function getStepStatus(stepId: string, currentStatus: TimelineStatus, lastMessag export default function TicketTimeline({ currentStatus, lastMessageBy }: TimelineProps) { return ( -
-
+
+ {/* Version mobile : vertical */} +
+ {TIMELINE_STEPS.map((step, index) => { + const status = getStepStatus(step.id, currentStatus, lastMessageBy); + const Icon = step.icon; + + return ( + +
+ {/* Icône */} +
+ + {status === "current" && ( +
+ )} +
+ + {/* Label */} +
+
+ {step.label} +
+
+
+ + {/* Connecteur vertical */} + {index < TIMELINE_STEPS.length - 1 && ( +
+
+
+ )} + + ); + })} +
+ + {/* Version desktop : horizontal */} +
{TIMELINE_STEPS.map((step, index) => { const status = getStepStatus(step.id, currentStatus, lastMessageBy); const Icon = step.icon; @@ -94,7 +161,7 @@ export default function TicketTimeline({ currentStatus, lastMessageBy }: Timelin
- {/* Connecteur */} + {/* Connecteur horizontal */} {index < TIMELINE_STEPS.length - 1 && (
{ + createServer(async (req, res) => { + try { + const parsedUrl = parse(req.url, true); + await handle(req, res, parsedUrl); + } catch (err) { + console.error('Error occurred handling', req.url, err); + res.statusCode = 500; + res.end('internal server error'); + } + }) + .once('error', (err) => { + console.error(err); + process.exit(1); + }) + .listen(port, hostname, () => { + const localIp = getLocalIp(); + console.log(`\n✨ Serveur Next.js démarré !\n`); + console.log(` 🏠 Local: http://localhost:${port}`); + console.log(` 📱 Network: http://${localIp}:${port}`); + console.log(`\n Pour accéder depuis mobile: http://${localIp}:${port}\n`); + }); +}); diff --git a/test-server.js b/test-server.js new file mode 100644 index 0000000..ea9f5c9 --- /dev/null +++ b/test-server.js @@ -0,0 +1,104 @@ +curl http://192.168.1.122:3002const http = require('http'); +const os = require('os'); + +function getLocalIp() { + const interfaces = os.networkInterfaces(); + for (const name of Object.keys(interfaces)) { + for (const iface of interfaces[name]) { + const { address, family, internal } = iface; + if (family === 'IPv4' && !internal) { + return address; + } + } + } + return 'localhost'; +} + +const hostname = '0.0.0.0'; +const port = 3002; +const localIp = getLocalIp(); + +const server = http.createServer((req, res) => { + console.log(`📨 Requête reçue de: ${req.socket.remoteAddress}:${req.socket.remotePort}`); + console.log(` URL: ${req.url}`); + console.log(` Host header: ${req.headers.host}`); + + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.end(` + + + + Test Serveur + + + + +
+
+

Serveur accessible !

+

🎉 Félicitations ! Si vous voyez cette page, le serveur fonctionne correctement.

+ +
+

Informations de connexion :

+
    +
  • Adresse IP locale : ${localIp}
  • +
  • Port : ${port}
  • +
  • Votre IP client : ${req.socket.remoteAddress}
  • +
  • Host demandé : ${req.headers.host}
  • +
+
+ +

URLs d'accès :

+ +
+ + + `); +}); + +server.listen(port, hostname, () => { + console.log('\n🚀 ========================================'); + console.log(' SERVEUR DE TEST DÉMARRÉ'); + console.log('========================================\n'); + console.log(` ✅ Le serveur écoute sur toutes les interfaces (${hostname}:${port})\n`); + console.log('📱 TESTEZ CES URLs DEPUIS VOTRE MOBILE :\n'); + console.log(` 1️⃣ http://${localIp}:${port}`); + console.log(` 2️⃣ http://${os.hostname()}.local:${port}`); + console.log(` 3️⃣ http://Renauds-MacBook-Air.local:${port}\n`); + console.log('💻 Sur ce Mac, utilisez :'); + console.log(` http://localhost:${port}\n`); + console.log('========================================\n'); +}); + +server.on('error', (e) => { + if (e.code === 'EADDRINUSE') { + console.error(`❌ Le port ${port} est déjà utilisé !`); + } else { + console.error('❌ Erreur serveur:', e); + } +});