Compare commits
No commits in common. "fa41dda3a7ddffe84323844be87b228129b1a6fc" and "d7d67b274b756b13faf0e84e2772f5f35b3b83db" have entirely different histories.
fa41dda3a7
...
d7d67b274b
@ -351,45 +351,39 @@ export default function FoldersPage() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleConnectionFlow = async () => {
|
if (isConnected) {
|
||||||
if (!isConnected) return;
|
|
||||||
|
|
||||||
const userStore = UserStore.getInstance();
|
|
||||||
const messageBus = MessageBus.getInstance(iframeUrl);
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
try {
|
messageBus.getProcesses().then((processes: any) => {
|
||||||
await messageBus.isReady();
|
setProcesses(processes);
|
||||||
|
});
|
||||||
let pairingId = userStore.getUserPairingId();
|
});
|
||||||
|
}
|
||||||
// 1️⃣ Créer le pairing si non existant
|
|
||||||
if (!pairingId) {
|
|
||||||
console.log("🚀 No pairing found — creating new pairing...");
|
|
||||||
pairingId = await messageBus.createUserPairing();
|
|
||||||
console.log("✅ Pairing created:", 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);
|
|
||||||
|
|
||||||
// 3️⃣ Charger les myProcesses
|
|
||||||
const myProcesses = await messageBus.getMyProcesses();
|
|
||||||
setMyProcesses(myProcesses);
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error("❌ Error during pairing or process loading:", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleConnectionFlow();
|
|
||||||
}, [isConnected, iframeUrl]);
|
}, [isConnected, iframeUrl]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected && processes !== null) {
|
||||||
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
|
messageBus.getMyProcesses().then((res: string[]) => {
|
||||||
|
setMyProcesses(res);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isConnected, processes]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected && userPairingId === null) {
|
||||||
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
|
messageBus.getUserPairingId().then((userPairingId: string) => {
|
||||||
|
UserStore.getInstance().pair(userPairingId);
|
||||||
|
setUserPairingId(UserStore.getInstance().getUserPairingId());
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isConnected, userPairingId, processes]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Simuler le chargement des dossiers
|
// Simuler le chargement des dossiers
|
||||||
const loadFolders = () => {
|
const loadFolders = () => {
|
||||||
|
|||||||
@ -282,45 +282,39 @@ export default function DashboardPage() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleConnectionFlow = async () => {
|
if (isConnected) {
|
||||||
if (!isConnected) return;
|
|
||||||
|
|
||||||
const userStore = UserStore.getInstance();
|
|
||||||
const messageBus = MessageBus.getInstance(iframeUrl);
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
try {
|
messageBus.getProcesses().then((processes: any) => {
|
||||||
await messageBus.isReady();
|
setProcesses(processes);
|
||||||
|
});
|
||||||
let pairingId = userStore.getUserPairingId();
|
});
|
||||||
|
}
|
||||||
// 1️⃣ Créer le pairing si non existant
|
|
||||||
if (!pairingId) {
|
|
||||||
console.log("🚀 No pairing found — creating new pairing...");
|
|
||||||
pairingId = await messageBus.createUserPairing();
|
|
||||||
console.log("✅ Pairing created:", 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);
|
|
||||||
|
|
||||||
// 3️⃣ Charger les myProcesses
|
|
||||||
const myProcesses = await messageBus.getMyProcesses();
|
|
||||||
setMyProcesses(myProcesses);
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error("❌ Error during pairing or process loading:", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleConnectionFlow();
|
|
||||||
}, [isConnected, iframeUrl]);
|
}, [isConnected, iframeUrl]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected && processes !== null) {
|
||||||
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
|
messageBus.getMyProcesses().then((res: string[]) => {
|
||||||
|
setMyProcesses(res);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isConnected, processes]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected && userPairingId === null) {
|
||||||
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
|
messageBus.isReady().then(() => {
|
||||||
|
messageBus.getUserPairingId().then((userPairingId: string) => {
|
||||||
|
UserStore.getInstance().pair(userPairingId);
|
||||||
|
setUserPairingId(UserStore.getInstance().getUserPairingId());
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isConnected, userPairingId, processes]);
|
||||||
|
|
||||||
const handleOpenModal = (type: FolderType) => {
|
const handleOpenModal = (type: FolderType) => {
|
||||||
setFolderType(type);
|
setFolderType(type);
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export default function HomePage() {
|
|||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
setShowAuthModal(false);
|
setShowAuthModal(false);
|
||||||
router.push("/dashboard")
|
router.push("/dashboard")
|
||||||
|
console.log('Auth Connect - Connexion établie, le useEffect se chargera de récupérer le userPairingId');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleAuthClose = useCallback(() => {
|
const handleAuthClose = useCallback(() => {
|
||||||
|
|||||||
@ -269,17 +269,7 @@ function ProcessesViewer({ processes, myProcesses, onProcessesUpdate }: Processe
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="text-sm text-gray-500 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-100"
|
className="text-sm text-gray-500 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-100"
|
||||||
onClick={(e) => {
|
onClick={(e) => { e.stopPropagation(); setEditingField({ processId, stateId, key, value }); }}
|
||||||
e.stopPropagation();
|
|
||||||
if (isEditing) {
|
|
||||||
// Fermer le mode édition
|
|
||||||
setEditingField(null);
|
|
||||||
setTempValue(null);
|
|
||||||
} else {
|
|
||||||
// Ouvrir le mode édition
|
|
||||||
setEditingField({ processId, stateId, key, value });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{isEditing ? '✕' : '🔄'}
|
{isEditing ? '✕' : '🔄'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import IframeReference from './IframeReference';
|
import IframeReference from './IframeReference';
|
||||||
import EventBus from './EventBus';
|
import EventBus from './EventBus';
|
||||||
import UserStore from './UserStore';
|
import UserStore from './UserStore';
|
||||||
|
import { isProfileData, type ProfileCreated, type ProfileData } from './models/ProfileData';
|
||||||
import { isFolderData, type FolderCreated, type FolderData } from './models/FolderData';
|
import { isFolderData, type FolderCreated, type FolderData } from './models/FolderData';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import type { RoleDefinition } from './models/Roles';
|
import type { RoleDefinition } from './models/Roles';
|
||||||
@ -80,48 +81,6 @@ export default class MessageBus {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public createUserPairing(): Promise<string> {
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
|
||||||
this.checkToken().then(async () => {
|
|
||||||
const userStore = UserStore.getInstance();
|
|
||||||
const accessToken = userStore.getAccessToken();
|
|
||||||
if (!accessToken) {
|
|
||||||
return reject('No access token found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const correlationId = uuidv4();
|
|
||||||
this.initMessageListener(correlationId);
|
|
||||||
|
|
||||||
// ✅ Success listener
|
|
||||||
const unsubscribeSuccess = EventBus.getInstance().on('PAIRING_CREATED', (responseId: string, pairingId: string) => {
|
|
||||||
if (responseId !== correlationId) return;
|
|
||||||
unsubscribeSuccess();
|
|
||||||
unsubscribeError();
|
|
||||||
this.destroyMessageListener();
|
|
||||||
resolve(pairingId);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ❌ Error listener
|
|
||||||
const unsubscribeError = EventBus.getInstance().on('ERROR_CREATE_PAIRING', (responseId: string, error: string) => {
|
|
||||||
if (responseId !== correlationId) return;
|
|
||||||
unsubscribeError();
|
|
||||||
unsubscribeSuccess();
|
|
||||||
this.destroyMessageListener();
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 📨 Send CREATE_PAIRING message to iframe
|
|
||||||
this.sendMessage({
|
|
||||||
type: 'CREATE_PAIRING',
|
|
||||||
accessToken,
|
|
||||||
messageId: correlationId,
|
|
||||||
});
|
|
||||||
}).catch((err) => {
|
|
||||||
reject(`Failed to validate token before pairing: ${err}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getUserPairingId(): Promise<string> {
|
public getUserPairingId(): Promise<string> {
|
||||||
return new Promise<string>((resolve: (userPairingId: string) => void, reject: (error: string) => void) => {
|
return new Promise<string>((resolve: (userPairingId: string) => void, reject: (error: string) => void) => {
|
||||||
this.checkToken().then(() => {
|
this.checkToken().then(() => {
|
||||||
@ -378,6 +337,61 @@ export default class MessageBus {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createProfile(profileData: ProfileData, profilePrivateData: string[], roles: Record<string, RoleDefinition>): Promise<ProfileCreated> {
|
||||||
|
return new Promise<ProfileCreated>((resolve: (profileCreated: ProfileCreated) => void, reject: (error: string) => void) => {
|
||||||
|
this.checkToken().then(() => {
|
||||||
|
const userStore = UserStore.getInstance();
|
||||||
|
const accessToken = userStore.getAccessToken()!;
|
||||||
|
|
||||||
|
const correlationId = uuidv4();
|
||||||
|
this.initMessageListener(correlationId);
|
||||||
|
|
||||||
|
const unsubscribe = EventBus.getInstance().on('PROCESS_CREATED', (responseId: string, processCreated: any) => {
|
||||||
|
if (responseId !== correlationId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsubscribe();
|
||||||
|
this.destroyMessageListener();
|
||||||
|
// Return value must contain the data commited in the new process
|
||||||
|
const profileData = processCreated.processData;
|
||||||
|
if (!profileData || !isProfileData(profileData)) {
|
||||||
|
reject('Returned invalid profile data');
|
||||||
|
}
|
||||||
|
if (!processCreated.processId || typeof processCreated.processId !== 'string') {
|
||||||
|
console.error('Returned invalid process id');
|
||||||
|
reject('Returned invalid process id');
|
||||||
|
}
|
||||||
|
// TODO check that process is of type Process
|
||||||
|
|
||||||
|
const profileCreated: ProfileCreated = {
|
||||||
|
processId: processCreated.processId,
|
||||||
|
process: processCreated.process,
|
||||||
|
profileData
|
||||||
|
};
|
||||||
|
|
||||||
|
resolve(profileCreated);
|
||||||
|
});
|
||||||
|
|
||||||
|
const unsubscribeError = EventBus.getInstance().on('ERROR_PROCESS_CREATED', (responseId: string, error: string) => {
|
||||||
|
if (responseId !== correlationId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsubscribeError();
|
||||||
|
this.destroyMessageListener();
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.sendMessage({
|
||||||
|
type: 'CREATE_PROCESS',
|
||||||
|
processData: profileData,
|
||||||
|
privateFields: profilePrivateData,
|
||||||
|
roles,
|
||||||
|
accessToken
|
||||||
|
});
|
||||||
|
}).catch(console.error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public createFolder(folderData: FolderData, folderPrivateData: string[], roles: Record<string, RoleDefinition>): Promise<FolderCreated> {
|
public createFolder(folderData: FolderData, folderPrivateData: string[], roles: Record<string, RoleDefinition>): Promise<FolderCreated> {
|
||||||
return new Promise<FolderCreated>((resolve: (folderData: FolderCreated) => void, reject: (error: string) => void) => {
|
return new Promise<FolderCreated>((resolve: (folderData: FolderCreated) => void, reject: (error: string) => void) => {
|
||||||
this.checkToken().then(() => {
|
this.checkToken().then(() => {
|
||||||
@ -612,7 +626,7 @@ export default class MessageBus {
|
|||||||
console.error('[MessageBus] sendMessage: iframe not found');
|
console.error('[MessageBus] sendMessage: iframe not found');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[MessageBus] sendMessage:', message, 'to', this.origin);
|
console.log('[MessageBus] sendMessage:', message, 'to', this.origin);
|
||||||
iframe.contentWindow?.postMessage(message, this.origin);
|
iframe.contentWindow?.postMessage(message, this.origin);
|
||||||
}
|
}
|
||||||
@ -700,7 +714,7 @@ export default class MessageBus {
|
|||||||
EventBus.getInstance().emit('PROCESSES_RETRIEVED', correlationId, message.processes);
|
EventBus.getInstance().emit('PROCESSES_RETRIEVED', correlationId, message.processes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GET_MY_PROCESSES':
|
case 'GET_MY_PROCESSES':
|
||||||
if (this.errors[correlationId]) {
|
if (this.errors[correlationId]) {
|
||||||
const error = this.errors[correlationId];
|
const error = this.errors[correlationId];
|
||||||
delete this.errors[correlationId];
|
delete this.errors[correlationId];
|
||||||
@ -742,7 +756,7 @@ export default class MessageBus {
|
|||||||
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
|
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
|
||||||
EventBus.getInstance().emit('UPDATE_NOTIFIED', correlationId);
|
EventBus.getInstance().emit('UPDATE_NOTIFIED', correlationId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'STATE_VALIDATED':
|
case 'STATE_VALIDATED':
|
||||||
if (this.errors[correlationId]) {
|
if (this.errors[correlationId]) {
|
||||||
const error = this.errors[correlationId];
|
const error = this.errors[correlationId];
|
||||||
@ -775,18 +789,7 @@ export default class MessageBus {
|
|||||||
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
|
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
|
||||||
EventBus.getInstance().emit('PUBLIC_DATA_DECODED', correlationId, message.decodedData);
|
EventBus.getInstance().emit('PUBLIC_DATA_DECODED', correlationId, message.decodedData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'PAIRING_CREATED':
|
|
||||||
if (this.errors[correlationId]) {
|
|
||||||
const error = this.errors[correlationId];
|
|
||||||
delete this.errors[correlationId];
|
|
||||||
EventBus.getInstance().emit('ERROR_PAIRING_CREATED', correlationId, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EventBus.getInstance().emit('MESSAGE_RECEIVED', message);
|
|
||||||
EventBus.getInstance().emit('PAIRING_CREATED', correlationId, message.decodedData);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ERROR':
|
case 'ERROR':
|
||||||
console.error('Error:', message);
|
console.error('Error:', message);
|
||||||
this.errors[correlationId] = message.error;
|
this.errors[correlationId] = message.error;
|
||||||
|
|||||||
122
lib/4nk/models/ProfileData.ts
Normal file
122
lib/4nk/models/ProfileData.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import { isFileBlob, type FileBlob } from "./Data";
|
||||||
|
import type { RoleDefinition } from "./Roles";
|
||||||
|
|
||||||
|
export interface ProfileData {
|
||||||
|
name: string;
|
||||||
|
surname: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
address: string;
|
||||||
|
postalCode: string;
|
||||||
|
city: string;
|
||||||
|
country: string;
|
||||||
|
idDocument: FileBlob | null;
|
||||||
|
idCertified: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isProfileData(data: any): data is ProfileData{
|
||||||
|
if (typeof data !== 'object' || data === null) return false;
|
||||||
|
|
||||||
|
const requiredStringFields = [
|
||||||
|
'name',
|
||||||
|
'surname',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'address',
|
||||||
|
'postalCode',
|
||||||
|
'city',
|
||||||
|
'country',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const field of requiredStringFields) {
|
||||||
|
if (typeof data[field] !== 'string') return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requiredBooleanFields = [
|
||||||
|
'idCertified',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const field of requiredBooleanFields) {
|
||||||
|
if (typeof data[field] !== 'boolean') return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requiredFileFields = [
|
||||||
|
'idDocument',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const field of requiredFileFields) {
|
||||||
|
if (!isFileBlob(data[field]) && data[field] !== null) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyProfileData: ProfileData = {
|
||||||
|
name: '',
|
||||||
|
surname: '',
|
||||||
|
email: '',
|
||||||
|
phone: '',
|
||||||
|
address: '',
|
||||||
|
postalCode: '',
|
||||||
|
city: '',
|
||||||
|
country: '',
|
||||||
|
idDocument: null,
|
||||||
|
idCertified: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const profileDataFields: string[] = Object.keys(emptyProfileData);
|
||||||
|
|
||||||
|
const ProfilePublicFields: string[] = ['idCertified'];
|
||||||
|
|
||||||
|
export const ProfilePrivateFields = [
|
||||||
|
...profileDataFields.filter(key => !ProfilePublicFields.includes(key))
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface ProfileCreated {
|
||||||
|
processId: string,
|
||||||
|
process: any, // Process
|
||||||
|
profileData: ProfileData,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setDefaultProfileRoles(ownerId: string[], validatorId: string): Record<string, RoleDefinition> {
|
||||||
|
return {
|
||||||
|
demiurge: {
|
||||||
|
members: [...ownerId, validatorId],
|
||||||
|
validation_rules: [],
|
||||||
|
storages: []
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
members: ownerId,
|
||||||
|
validation_rules: [
|
||||||
|
{
|
||||||
|
quorum: 0.5,
|
||||||
|
fields: [...ProfilePrivateFields, 'roles'],
|
||||||
|
min_sig_member: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
storages: []
|
||||||
|
},
|
||||||
|
validator: {
|
||||||
|
members: [validatorId],
|
||||||
|
validation_rules: [
|
||||||
|
{
|
||||||
|
quorum: 0.5,
|
||||||
|
fields: ['idCertified', 'roles'],
|
||||||
|
min_sig_member: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quorum: 0.0,
|
||||||
|
fields: [...profileDataFields],
|
||||||
|
min_sig_member: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
storages: []
|
||||||
|
},
|
||||||
|
apophis: {
|
||||||
|
members: ownerId,
|
||||||
|
validation_rules: [],
|
||||||
|
storages: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user