diff --git a/app/dashboard/folders/[id]/roles/loading.tsx b/app/dashboard/folders/[id]/roles/loading.tsx deleted file mode 100644 index f15322a..0000000 --- a/app/dashboard/folders/[id]/roles/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Loading() { - return null -} diff --git a/app/dashboard/folders/[id]/roles/page.tsx b/app/dashboard/folders/[id]/roles/page.tsx deleted file mode 100644 index f9cf2dd..0000000 --- a/app/dashboard/folders/[id]/roles/page.tsx +++ /dev/null @@ -1,540 +0,0 @@ -"use client" - -import { useState, useEffect } from "react" -import { useRouter, useParams } from "next/navigation" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Badge } from "@/components/ui/badge" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { - Users, - UserPlus, - Search, - ArrowLeft, - Crown, - Edit, - Eye, - Shield, - UserCheck, - Trash2, - X, - CheckCircle, - XCircle, - Info, - Folder, -} from "lucide-react" - -interface FolderRole { - userId: string - userName: string - userEmail: string - userAvatar: string - role: "owner" | "editor" | "viewer" | "validator" | "contributor" - assignedDate: Date - assignedBy: string - defaultRole: "admin" | "editor" | "viewer" -} - -interface User { - id: string - name: string - email: string - avatar: string - defaultRole: "admin" | "editor" | "viewer" - department: string -} - -export default function FolderRolesPage() { - const router = useRouter() - const params = useParams() - const folderId = params.id as string - - const [folderName, setFolderName] = useState("") - const [folderRoles, setFolderRoles] = useState([]) - const [availableUsers, setAvailableUsers] = useState([]) - const [searchTerm, setSearchTerm] = useState("") - const [showAddUser, setShowAddUser] = useState(false) - const [selectedUser, setSelectedUser] = useState("") - const [selectedRole, setSelectedRole] = useState("viewer") - const [inviteMessage, setInviteMessage] = useState("") - const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null) - - // Simuler le chargement des données - useEffect(() => { - // Charger les informations du dossier - const folderNames: { [key: string]: string } = { - "1": "Contrats", - "2": "Rapports", - "3": "Projets", - "4": "Finance", - "5": "Ressources Humaines", - "6": "Marketing", - } - setFolderName(folderNames[folderId] || "Dossier") - - // Charger les rôles existants sur le dossier - const mockFolderRoles: FolderRole[] = [ - { - userId: "1", - userName: "Marie Dubois", - userEmail: "marie.dubois@docv.fr", - userAvatar: "MD", - role: "owner", - assignedDate: new Date("2024-01-01"), - assignedBy: "Système", - defaultRole: "admin", - }, - { - userId: "2", - userName: "Pierre Martin", - userEmail: "pierre.martin@docv.fr", - userAvatar: "PM", - role: "editor", - assignedDate: new Date("2024-01-10"), - assignedBy: "Marie Dubois", - defaultRole: "editor", - }, - { - userId: "5", - userName: "Julie Moreau", - userEmail: "julie.moreau@docv.fr", - userAvatar: "JM", - role: "validator", - assignedDate: new Date("2024-01-15"), - assignedBy: "Marie Dubois", - defaultRole: "admin", - }, - ] - setFolderRoles(mockFolderRoles) - - // Charger les utilisateurs disponibles (ceux qui n'ont pas encore de rôle sur ce dossier) - const allUsers: User[] = [ - { - id: "3", - name: "Sophie Laurent", - email: "sophie.laurent@docv.fr", - avatar: "SL", - defaultRole: "viewer", - department: "RH", - }, - { - id: "4", - name: "Thomas Rousseau", - email: "thomas.rousseau@docv.fr", - avatar: "TR", - defaultRole: "editor", - department: "Finance", - }, - ] - - const usersWithRoles = mockFolderRoles.map((fr) => fr.userId) - const available = allUsers.filter((user) => !usersWithRoles.includes(user.id)) - setAvailableUsers(available) - }, [folderId]) - - // Notification system - const showNotification = (type: "success" | "error" | "info", message: string) => { - setNotification({ type, message }) - setTimeout(() => setNotification(null), 3000) - } - - const getRoleIcon = (role: string) => { - switch (role) { - case "owner": - return - case "editor": - return - case "validator": - return - case "contributor": - return - case "viewer": - return - default: - return - } - } - - const getRoleColor = (role: string) => { - switch (role) { - case "owner": - return "bg-yellow-100 text-yellow-800 border-yellow-200" - case "editor": - return "bg-blue-100 text-blue-800 border-blue-200" - case "validator": - return "bg-green-100 text-green-800 border-green-200" - case "contributor": - return "bg-purple-100 text-purple-800 border-purple-200" - case "viewer": - return "bg-gray-100 text-gray-800 border-gray-200" - default: - return "bg-gray-100 text-gray-800 border-gray-200" - } - } - - const getDefaultRoleColor = (role: string) => { - switch (role) { - case "admin": - return "bg-red-100 text-red-800 border-red-200" - case "editor": - return "bg-blue-100 text-blue-800 border-blue-200" - case "viewer": - return "bg-gray-100 text-gray-800 border-gray-200" - default: - return "bg-gray-100 text-gray-800 border-gray-200" - } - } - - const handleAddUser = () => { - if (!selectedUser) return - - const user = availableUsers.find((u) => u.id === selectedUser) - if (!user) return - - const newRole: FolderRole = { - userId: user.id, - userName: user.name, - userEmail: user.email, - userAvatar: user.avatar, - role: selectedRole as "owner" | "editor" | "viewer" | "validator" | "contributor", - assignedDate: new Date(), - assignedBy: "Utilisateur actuel", - defaultRole: user.defaultRole, - } - - setFolderRoles((prev) => [...prev, newRole]) - setAvailableUsers((prev) => prev.filter((u) => u.id !== selectedUser)) - - showNotification("success", `${user.name} ajouté avec le rôle ${selectedRole}`) - - // Reset form - setSelectedUser("") - setSelectedRole("viewer") - setInviteMessage("") - setShowAddUser(false) - } - - const handleChangeRole = (userId: string, newRole: string) => { - setFolderRoles((prev) => - prev.map((fr) => - fr.userId === userId - ? { ...fr, role: newRole as "owner" | "editor" | "viewer" | "validator" | "contributor" } - : fr, - ), - ) - - const user = folderRoles.find((fr) => fr.userId === userId) - showNotification("success", `Rôle de ${user?.userName} mis à jour vers ${newRole}`) - } - - const handleRemoveUser = (userId: string) => { - const userRole = folderRoles.find((fr) => fr.userId === userId) - if (!userRole) return - - if (userRole.role === "owner") { - showNotification("error", "Impossible de supprimer le propriétaire du dossier") - return - } - - setFolderRoles((prev) => prev.filter((fr) => fr.userId !== userId)) - - // Remettre l'utilisateur dans la liste des disponibles - const user: User = { - id: userRole.userId, - name: userRole.userName, - email: userRole.userEmail, - avatar: userRole.userAvatar, - defaultRole: userRole.defaultRole, - department: "Département", // Valeur par défaut - } - setAvailableUsers((prev) => [...prev, user]) - - showNotification("success", `${userRole.userName} retiré du dossier`) - } - - const filteredRoles = folderRoles.filter( - (role) => - role.userName.toLowerCase().includes(searchTerm.toLowerCase()) || - role.userEmail.toLowerCase().includes(searchTerm.toLowerCase()), - ) - - return ( -
- {/* Notification */} - {notification && ( -
- {notification.type === "success" && } - {notification.type === "error" && } - {notification.type === "info" && } - {notification.message} - -
- )} - - {/* Header */} -
- -
-
- -
-
-

Gestion des rôles - Dossier "{folderName}"

-

Gérez les permissions d'accès et les rôles des utilisateurs sur ce dossier

-
-
-
- - {/* Stats supprimées selon la consigne */} - - {/* Search and Add */} - - -
-
- - setSearchTerm(e.target.value)} - className="pl-10" - /> -
- -
- - {showAddUser && ( -
-

Ajouter un utilisateur au dossier

-
-
- - -
-
- - -
-
- - -
-
-
- )} -
-
- - {/* Roles List */} - - - Utilisateurs avec accès au dossier - - -
- - - - - - - - - - - - - {filteredRoles.map((roleAssignment) => ( - - - - - - - - - ))} - -
UtilisateurRôle par défautRôle sur ce dossierAssigné leAssigné parActions
-
-
- {roleAssignment.userAvatar} -
-
-

{roleAssignment.userName}

-

{roleAssignment.userEmail}

-
-
-
- - {roleAssignment.defaultRole} - - - - {roleAssignment.assignedDate.toLocaleDateString("fr-FR")}{roleAssignment.assignedBy} - {roleAssignment.role !== "owner" && ( - - )} -
-
- - {filteredRoles.length === 0 && ( -
- -

Aucun utilisateur trouvé

-

Essayez de modifier vos critères de recherche

-
- )} -
-
-
- ) -} diff --git a/app/dashboard/folders/loading.tsx b/app/dashboard/folders/loading.tsx deleted file mode 100644 index ea47616..0000000 --- a/app/dashboard/folders/loading.tsx +++ /dev/null @@ -1,75 +0,0 @@ -export default function FoldersLoading() { - return ( -
- {/* Header Skeleton */} -
-
-
-
-
-
-
-
-
-
- - {/* Breadcrumb Skeleton */} -
-
-
- - {/* Stats Cards Skeleton */} -
- {[...Array(4)].map((_, i) => ( -
-
-
-
-
-
-
-
-
- ))} -
- - {/* Search and Filters Skeleton */} -
-
-
-
-
-
-
-
-
-
-
-
- - {/* Folders Grid Skeleton */} -
-
- {[...Array(8)].map((_, i) => ( -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ))} -
-
-
- ) -} diff --git a/app/dashboard/folders/page.tsx b/app/dashboard/folders/page.tsx deleted file mode 100644 index 65373d3..0000000 --- a/app/dashboard/folders/page.tsx +++ /dev/null @@ -1,549 +0,0 @@ -"use client" - -import { useState, useEffect, useCallback } from "react" -import { Card, CardContent } from "@/components/ui/card" -import { Badge } from "@/components/ui/badge" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { - Folder, - Search, - FolderPlus, - Clock, - ChevronRight, - SortAsc, - SortDesc, - X, - MessageSquare, - List, -} from "lucide-react" -import { FolderData, FolderCreated, FolderPrivateFields, setDefaultFolderRoles } from "@/lib/4nk/models/FolderData" -import MessageBus from "@/lib/4nk/MessageBus" -import { iframeUrl } from "@/app/page" -import UserStore from "@/lib/4nk/UserStore" -import FolderModal from "@/components/4nk/FolderModal" -import AuthModal from "@/components/4nk/AuthModal" -import Iframe from "@/components/4nk/Iframe" -import FolderChat from "@/components/4nk/FolderChat" - -type FolderType = 'contrat' | 'projet' | 'rapport' | 'finance' | 'rh' | 'marketing' | 'autre'; - -export default function FoldersPage() { - const [searchTerm, setSearchTerm] = useState("") - const [sortBy, setSortBy] = useState("updated_at") - const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc") - const [currentPath, setCurrentPath] = useState(["Racine"]) - const [folderType, setFolderType] = useState(null); - const [isModalOpen, setIsModalOpen] = useState(false); - const [activeTab, setActiveTab] = useState<"folders" | "chat">("folders"); - - // 4NK Integration states - const [isConnected, setIsConnected] = useState(false) - const [showAuthModal, setShowAuthModal] = useState(false) - const [processes, setProcesses] = useState(null) - const [myProcesses, setMyProcesses] = useState([]) - const [userPairingId, setUserPairingId] = useState(null) - const [folderProcesses, setFolderProcesses] = useState(null) - const [myFolderProcesses, setMyFolderProcesses] = useState([]) - const [folderPrivateData, setFolderPrivateData] = useState>>({}) - const [loadingFolders, setLoadingFolders] = useState(false) - - // Modal states - const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null) - - const [folders, setFolders] = useState([]) - const [stats, setStats] = useState({ - total: 0 - }) - - // Notification system - const showNotification = (type: "success" | "error" | "info", message: string) => { - setNotification({ type, message }) - setTimeout(() => setNotification(null), 5000) - } - - // Function to fetch folder private data - const fetchFolderPrivateData = useCallback(async (processId: string, stateId: string) => { - if (!myFolderProcesses.includes(processId)) return; - try { - const messageBus = MessageBus.getInstance(iframeUrl); - await messageBus.isReady(); - const data = await messageBus.getData(processId, stateId); - setFolderPrivateData(prev => ({ ...prev, [stateId]: data })); - } catch (err) { - console.error('Error fetching folder private data:', err); - } - }, [myFolderProcesses]); - - // Function to load folders from 4NK processes (adapted to new FolderData model) - const loadFoldersFrom4NK = useCallback(() => { - if (!folderProcesses) return; - - const folderData: FolderData[] = []; - let hasAllPrivateData = true; - let hasFoldersToLoad = false; - const missingPrivateData: Array<{processId: string, stateId: string}> = []; - - Object.entries(folderProcesses).forEach(([processId, process]: [string, any]) => { - // Only include processes that belong to the user (myFolderProcesses) - if (!myFolderProcesses.includes(processId)) return; - - // Check if this process has a folderNumber in pcd_commitment - const latestState = process.states[0]; - if (!latestState) return; - - const folderNumber = latestState.pcd_commitment?.folderNumber; - if (!folderNumber) return; // Skip processes without folderNumber - - hasFoldersToLoad = true; // We have at least one folder to load - - // Get private data for this state if available - const privateData = folderPrivateData[latestState.state_id]; - - // If we don't have private data yet, mark as incomplete and collect missing data - if (!privateData) { - hasAllPrivateData = false; - missingPrivateData.push({processId, stateId: latestState.state_id}); - return; // Skip creating folder until we have private data - } - - // Create folder with new simplified model - const folder: FolderData = { - folderNumber: folderNumber, - name: privateData.name || `Dossier ${folderNumber}`, - description: privateData.description || '', - created_at: privateData.created_at || new Date().toISOString(), - updated_at: privateData.updated_at || new Date().toISOString(), - notes: privateData.notes || [] - }; - - folderData.push(folder); - }); - - // Manage loading state - if (hasFoldersToLoad && !hasAllPrivateData) { - setLoadingFolders(true); - // Fetch missing private data (but only once per missing item) - missingPrivateData.forEach(({processId, stateId}) => { - if (!folderPrivateData[stateId]) { - fetchFolderPrivateData(processId, stateId); - } - }); - } else if (hasAllPrivateData) { - setLoadingFolders(false); - setFolders(folderData); - - // Update stats - setStats({ - total: folderData.length - }); - } - }, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData]); - - // 4NK Integration useEffects - useEffect(() => { - const userStore = UserStore.getInstance(); - const connected = userStore.isConnected(); - const pairingId = userStore.getUserPairingId(); - - console.log('Initial 4NK state:', { connected, pairingId }); - setIsConnected(connected); - setUserPairingId(pairingId); - }, []); - - useEffect(() => { - const handleConnectionFlow = async () => { - if (!isConnected) return; - - try { - const messageBus = MessageBus.getInstance(iframeUrl); - await messageBus.isReady(); - - const userStore = UserStore.getInstance(); - let pairingId = userStore.getUserPairingId(); - - // 1️⃣ Créer ou récupérer le pairing - if (!pairingId) { - pairingId = await messageBus.createUserPairing(); - console.log("✅ Pairing created:", pairingId); - - if (pairingId) { - userStore.pair(pairingId); - setUserPairingId(pairingId); - } - } else { - console.log("🔗 Already paired with ID:", pairingId); - } - - // 2️⃣ Charger les processes - const processes = await messageBus.getProcesses(); - setProcesses(processes); - setFolderProcesses(processes); - - // 3️⃣ Charger les myProcesses - const myProcesses = await messageBus.getMyProcesses(); - setMyProcesses(myProcesses); - setMyFolderProcesses(myProcesses); - - } catch (err) { - console.error("❌ Error during pairing or process loading:", err); - } - }; - - handleConnectionFlow(); - }, [isConnected, iframeUrl]); - - // Load folders from 4NK when folder processes are available - useEffect(() => { - if (folderProcesses && myFolderProcesses.length >= 0) { - loadFoldersFrom4NK(); - } - }, [folderProcesses, myFolderProcesses, loadFoldersFrom4NK]); - - // Filter and sort folders - const filteredFolders = folders.filter(folder => { - const matchesSearch = folder.name.toLowerCase().includes(searchTerm.toLowerCase()) || - folder.description.toLowerCase().includes(searchTerm.toLowerCase()) || - folder.folderNumber.toLowerCase().includes(searchTerm.toLowerCase()) - - return matchesSearch - }) - - const sortedFolders = [...filteredFolders].sort((a, b) => { - let aValue: any, bValue: any - - switch (sortBy) { - case "name": - aValue = a.name.toLowerCase() - bValue = b.name.toLowerCase() - break - case "created_at": - aValue = new Date(a.created_at) - bValue = new Date(b.created_at) - break - case "updated_at": - aValue = new Date(a.updated_at) - bValue = new Date(b.updated_at) - break - default: - aValue = a.name.toLowerCase() - bValue = b.name.toLowerCase() - } - - if (sortOrder === "asc") { - return aValue < bValue ? -1 : aValue > bValue ? 1 : 0 - } else { - return aValue > bValue ? -1 : aValue < bValue ? 1 : 0 - } - }) - - - // Modal handlers - const handleOpenModal = (type: FolderType) => { - setFolderType(type); - setIsModalOpen(true); - }; - - const handleCloseModal = () => { - setIsModalOpen(false); - setFolderType(null); - }; - - const handleSaveNewFolder = useCallback( - (folderData: FolderData) => { - if (!isConnected || !userPairingId) { - console.error('Conditions non remplies:', { isConnected, userPairingId }); - showNotification( - "error", - `Vous devez être connecté à 4NK pour créer un dossier (Connected: ${isConnected}, PairingId: ${userPairingId ? 'OK' : 'NULL'})` - ); - return; - } - - const roles = setDefaultFolderRoles(userPairingId); - const folderPrivateFields = FolderPrivateFields; - - MessageBus.getInstance(iframeUrl) - .createFolder(folderData, folderPrivateFields, roles) - .then((_folderCreated: FolderCreated) => { - const firstStateId = _folderCreated.process.states[0].state_id; - MessageBus.getInstance(iframeUrl) - .notifyProcessUpdate(_folderCreated.processId, firstStateId) - .then(async () => { - // Recharger les processes et myProcesses - const messageBus = MessageBus.getInstance(iframeUrl); - const [processes, myProcesses] = await Promise.all([ - messageBus.getProcesses(), - messageBus.getMyProcesses() - ]); - - setProcesses(processes); - setFolderProcesses(processes); - setMyProcesses(myProcesses); - setMyFolderProcesses(myProcesses); - - showNotification("success", "Dossier créé avec succès !"); - handleCloseModal(); - }); - }) - .catch((error: any) => { - console.error('Erreur lors de la création du dossier:', error); - showNotification("error", "Erreur lors de la création du dossier"); - }); - }, - [isConnected, userPairingId] - ); - - // Auth connection handler - const handleAuthConnect = useCallback(() => { - setIsConnected(true); - setShowAuthModal(false); - console.log('Auth Connect - Connexion établie, le useEffect se chargera de récupérer le userPairingId'); - showNotification("success", "Connexion 4NK réussie"); - }, []); - - const handleAuthClose = useCallback(() => { - setShowAuthModal(false); - }, []); - - - return ( -
- {/* Sidebar */} -
-
-

Dossiers

-

Gérez vos dossiers 4NK

-
- -
-
-
- Total - {stats.total} -
-
-
- - {/* 4NK Connection Status */} -
-
- 4NK Status - - {isConnected ? "Connecté" : "Déconnecté"} - -
- {!isConnected && ( - - )} -
-
- - {/* Main Content */} -
- {/* Header */} -
-
-
- {currentPath.map((path, index) => ( -
- {index > 0 && } - {path} -
- ))} -
- -
- {activeTab === "folders" && ( - - )} -
-
- - {/* Tabs */} -
-
- - -
-
- - {/* Search and filters - only show for folders tab */} - {activeTab === "folders" && ( -
-
- - setSearchTerm(e.target.value)} - className="pl-10" - /> -
- -
- -
-
- )} -
- - {/* Content */} -
- {activeTab === "folders" ? ( -
- {loadingFolders ? ( -
-
-
-

Chargement des dossiers...

-
-
- ) : sortedFolders.length === 0 ? ( -
-
- -

Aucun dossier

-

- {searchTerm ? "Aucun dossier ne correspond à votre recherche." : "Commencez par créer votre premier dossier."} -

- {!searchTerm && ( - - )} -
-
- ) : ( -
- {/* Folder list */} -
- {sortedFolders.map((folder) => ( - - -
-
- -
-

{folder.name}

-

{folder.description}

-
- #{folder.folderNumber} - - - {new Date(folder.updated_at).toLocaleDateString()} - -
-
-
- -
- {folder.notes.length > 0 && ( - {folder.notes.length} notes - )} -
-
-
-
- ))} -
-
- )} -
- ) : ( - - )} -
-
- - {/* Modals */} - {isModalOpen && ( - - )} - - {showAuthModal && ( - - )} - - {/* Notification */} - {notification && ( -
-
-
- {notification.message} - -
-
-
- )} - - {/* 4NK Iframe - only show when connected */} - {isConnected &&