Now we can add a member to a folder with autocompletion
This commit is contained in:
parent
a91ca01f14
commit
c751809411
@ -96,7 +96,6 @@ export default function DashboardPage() {
|
||||
const [folderType, setFolderType] = useState<FolderType | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null)
|
||||
|
||||
const [selectedFolder, setSelectedFolder] = useState<EnrichedFolderData | null>(null);
|
||||
|
||||
const {
|
||||
@ -104,6 +103,7 @@ export default function DashboardPage() {
|
||||
userPairingId,
|
||||
folders,
|
||||
loadingFolders,
|
||||
members,
|
||||
setFolderProcesses,
|
||||
setMyFolderProcesses,
|
||||
setFolderPrivateData
|
||||
@ -131,20 +131,32 @@ export default function DashboardPage() {
|
||||
};
|
||||
|
||||
const handleSaveNewFolder = useCallback(
|
||||
(folderData: FolderData) => {
|
||||
(folderData: FolderData, selectedMembers: string[]) => {
|
||||
if (!isConnected || !userPairingId) {
|
||||
showNotification("error", "Vous devez être connecté à 4NK pour créer un dossier");
|
||||
return;
|
||||
}
|
||||
|
||||
// Crée les rôles par défaut (probablement 'owner' = vous)
|
||||
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(() => {
|
||||
|
||||
// Fusionne votre userPairingId avec les membres sélectionnés
|
||||
// On utilise un Set pour éviter les doublons
|
||||
const allOwnerMembers = new Set([
|
||||
...roles.owner.members, // Membres par défaut (vous)
|
||||
userPairingId, // S'assurer que vous y êtes
|
||||
...selectedMembers // Ajoute les nouveaux membres
|
||||
]);
|
||||
|
||||
// Met à jour la liste des membres pour le rôle 'owner'
|
||||
// (Vous pouvez ajuster "owner" pour un autre rôle si nécessaire)
|
||||
roles.owner.members = Array.from(allOwnerMembers);
|
||||
console.log(roles);
|
||||
|
||||
MessageBus.getInstance(iframeUrl).createFolder(folderData, folderPrivateFields, roles).then((_folderCreated: FolderCreated) => {
|
||||
MessageBus.getInstance(iframeUrl).notifyProcessUpdate(_folderCreated.processId, _folderCreated.process.states[0].state_id).then(() => {
|
||||
MessageBus.getInstance(iframeUrl).validateState(_folderCreated.processId, _folderCreated.process.states[0].state_id).then((_updatedProcess: any) => {
|
||||
const { processId, process } = _folderCreated;
|
||||
|
||||
setFolderProcesses((prevProcesses: any) => ({ ...prevProcesses, [processId]: process }));
|
||||
@ -152,11 +164,12 @@ export default function DashboardPage() {
|
||||
if (prevMyProcesses.includes(processId)) return prevMyProcesses;
|
||||
return [...prevMyProcesses, processId];
|
||||
});
|
||||
setFolderPrivateData((prevData) => ({ ...prevData, [firstStateId]: folderData }));
|
||||
setFolderPrivateData((prevData) => ({ ...prevData, [_folderCreated.process.states[0].state_id]: folderData }));
|
||||
|
||||
showNotification("success", "Dossier créé avec succès !");
|
||||
handleCloseModal();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('Erreur lors de la création du dossier:', error);
|
||||
@ -319,6 +332,7 @@ export default function DashboardPage() {
|
||||
onSave={handleSaveNewFolder}
|
||||
onCancel={handleCloseModal}
|
||||
folderType={folderType || "autre"}
|
||||
members={members}
|
||||
/>
|
||||
)}
|
||||
{notification && (
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
import React, { useEffect, useState, memo } from 'react';
|
||||
import Modal from './Modal';
|
||||
import type { FolderData } from '@/lib/4nk/models/FolderData';
|
||||
import { MemberAutocomplete } from '../ui/member-autocomplete';
|
||||
|
||||
type FolderType = 'contrat' | 'projet' | 'rapport' | 'finance' | 'rh' | 'marketing' | 'autre';
|
||||
|
||||
interface FolderModalProps {
|
||||
folder?: FolderData;
|
||||
onSave?: (folderData: FolderData) => void;
|
||||
// --- MODIFIÉ ---
|
||||
onSave?: (folderData: FolderData, selectedMembers: string[]) => void;
|
||||
onCancel?: () => void;
|
||||
readOnly?: boolean;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
folderType?: FolderType;
|
||||
// --- NOUVEAU ---
|
||||
members?: string[]; // Liste des membres disponibles
|
||||
renderExtraFields?: (
|
||||
folderData: FolderData,
|
||||
setFolderData: React.Dispatch<React.SetStateAction<FolderData>>
|
||||
@ -24,7 +28,9 @@ const defaultFolder: FolderData = {
|
||||
description: '',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
notes: []
|
||||
notes: [],
|
||||
messages: [],
|
||||
messages_owner: []
|
||||
};
|
||||
|
||||
function capitalize(s?: string) {
|
||||
@ -32,7 +38,7 @@ function capitalize(s?: string) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
}
|
||||
|
||||
// Mapping des couleurs par type de dossier
|
||||
// Mapping des couleurs
|
||||
const folderColors: Record<FolderType, { bg: string; border: string; focus: string; button: string }> = {
|
||||
contrat: { bg: 'bg-blue-50 dark:bg-blue-900', border: 'border-blue-300 dark:border-blue-700', focus: 'focus:ring-blue-400 dark:focus:ring-blue-600', button: 'bg-blue-500 hover:bg-blue-600' },
|
||||
projet: { bg: 'bg-green-50 dark:bg-green-900', border: 'border-green-300 dark:border-green-700', focus: 'focus:ring-green-400 dark:focus:ring-green-600', button: 'bg-green-500 hover:bg-green-600' },
|
||||
@ -51,15 +57,19 @@ function FolderModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
folderType = 'autre',
|
||||
members = [],
|
||||
renderExtraFields
|
||||
}: FolderModalProps) {
|
||||
const [folderData, setFolderData] = useState<FolderData>({ ...defaultFolder, ...folder });
|
||||
const [currentNote, setCurrentNote] = useState('');
|
||||
// --- NOUVEAU: État pour les membres sélectionnés ---
|
||||
const [selectedMembers, setSelectedMembers] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setFolderData({ ...defaultFolder, ...(folder || {}) });
|
||||
setCurrentNote('');
|
||||
setSelectedMembers([]); // <-- MODIFIÉ: Réinitialise les membres
|
||||
}
|
||||
}, [isOpen, folder]);
|
||||
|
||||
@ -70,6 +80,14 @@ function FolderModal({
|
||||
setFolderData(prev => ({ ...(prev as any), [name]: value } as FolderData));
|
||||
};
|
||||
|
||||
const handleMemberToggle = (memberId: string) => {
|
||||
setSelectedMembers(prev =>
|
||||
prev.includes(memberId)
|
||||
? prev.filter(id => id !== memberId)
|
||||
: [...prev, memberId]
|
||||
);
|
||||
};
|
||||
|
||||
const addNote = () => {
|
||||
const v = currentNote.trim();
|
||||
if (!v) return;
|
||||
@ -83,7 +101,7 @@ function FolderModal({
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
onSave?.({ ...folderData, updated_at: new Date().toISOString() });
|
||||
onSave?.({ ...folderData, updated_at: new Date().toISOString() }, selectedMembers);
|
||||
onClose();
|
||||
};
|
||||
|
||||
@ -139,6 +157,18 @@ function FolderModal({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Membres */}
|
||||
{!readOnly && (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-100">Membres</h3>
|
||||
<MemberAutocomplete
|
||||
allMembers={members}
|
||||
selectedMembers={selectedMembers}
|
||||
onChange={setSelectedMembers} // On passe le setter de l'état
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Notes */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-100">Notes</h3>
|
||||
|
||||
@ -32,10 +32,12 @@ type FourNKContextType = {
|
||||
folderPrivateData: Record<string, Record<string, any>>;
|
||||
folders: EnrichedFolderData[]; // <-- Utilise le type enrichi
|
||||
loadingFolders: boolean;
|
||||
members: string[];
|
||||
|
||||
setFolderProcesses: React.Dispatch<React.SetStateAction<any>>;
|
||||
setMyFolderProcesses: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
setFolderPrivateData: React.Dispatch<React.SetStateAction<Record<string, Record<string, any>>>>;
|
||||
setMembers: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
};
|
||||
|
||||
const FourNKContext = createContext<FourNKContextType | undefined>(undefined);
|
||||
@ -44,6 +46,7 @@ export function FourNKProvider({ children }: { children: ReactNode }) {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [userPairingId, setUserPairingId] = useState<string | null>(null);
|
||||
const [processes, setProcesses] = useState<any>(null);
|
||||
const [members, setMembers] = useState<string[]>([]);;
|
||||
const [myProcesses, setMyProcesses] = useState<string[]>([]);
|
||||
const [folderProcesses, setFolderProcesses] = useState<any>(null);
|
||||
const [myFolderProcesses, setMyFolderProcesses] = useState<string[]>([]);
|
||||
@ -124,7 +127,39 @@ export function FourNKProvider({ children }: { children: ReactNode }) {
|
||||
setFolders(folderData);
|
||||
setLoadingFolders(false);
|
||||
}
|
||||
}, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData]);
|
||||
}, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData, setFolders, setLoadingFolders]); // J'ai ajouté setFolders et setLoadingFolders aux dépendances
|
||||
|
||||
const loadMembersFrom4NK = useCallback(() => {
|
||||
if (!processes || !userPairingId) return;
|
||||
|
||||
const memberList: string[] = [];
|
||||
const EXCLUDED_STATE_ID = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
Object.entries(processes).forEach(([processId, process]: [string, any]) => {
|
||||
const validStates = process.states.filter(
|
||||
state => state && state.state_id !== EXCLUDED_STATE_ID
|
||||
);
|
||||
if (validStates.length === 0) return;
|
||||
|
||||
const referenceState = validStates.find(
|
||||
state => state.pcd_commitment?.pairedAddresses
|
||||
);
|
||||
if (!referenceState) return;
|
||||
|
||||
const userAddress = referenceState.commited_in
|
||||
|
||||
memberList.push(userAddress);
|
||||
});
|
||||
|
||||
// Filtrer la liste pour enlever l'ID de l'utilisateur connecté
|
||||
const filteredMemberList = memberList.filter(
|
||||
member => member !== userPairingId
|
||||
);
|
||||
|
||||
// Sauvegarder la liste filtrée dans l'état
|
||||
setMembers(filteredMemberList);
|
||||
|
||||
}, [processes, userPairingId]);
|
||||
|
||||
// Chargement initial des données 4NK
|
||||
useEffect(() => {
|
||||
@ -176,6 +211,11 @@ export function FourNKProvider({ children }: { children: ReactNode }) {
|
||||
loadFoldersFrom4NK();
|
||||
}, [loadFoldersFrom4NK]);
|
||||
|
||||
// Re-calculer les membres lorsque les données changent
|
||||
useEffect(() => {
|
||||
loadMembersFrom4NK();
|
||||
}, [loadMembersFrom4NK]);
|
||||
|
||||
|
||||
const value = {
|
||||
isConnected,
|
||||
@ -187,9 +227,11 @@ export function FourNKProvider({ children }: { children: ReactNode }) {
|
||||
folderPrivateData,
|
||||
folders,
|
||||
loadingFolders,
|
||||
members,
|
||||
setFolderProcesses,
|
||||
setMyFolderProcesses,
|
||||
setFolderPrivateData,
|
||||
setMembers,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user