Compare commits
6 Commits
24a8be727c
...
e6b9f58cea
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e6b9f58cea | ||
![]() |
8636d37d29 | ||
![]() |
a25e1b4ae5 | ||
![]() |
7807ae315f | ||
![]() |
2084b99978 | ||
![]() |
d5088d9e36 |
44
src/App.tsx
44
src/App.tsx
@ -11,7 +11,7 @@ import UserStore from './sdk/UserStrore';
|
||||
import Iframe from './sdk/Iframe'
|
||||
import BlockchainViewer from './components/ProcessesViewer';
|
||||
import FolderModal from './components/FolderModal';
|
||||
import type { ProfileCreated, ProfileData } from './sdk/models/ProfileData'
|
||||
import { ProfilePrivateFields, setDefaultProfileRoles, type ProfileCreated, type ProfileData } from './sdk/models/ProfileData'
|
||||
import { FolderPrivateFields, setDefaultFolderRoles, type FolderCreated, type FolderData } from './sdk/models/FolderData'
|
||||
|
||||
const iframeUrl = 'https://dev3.4nkweb.com'
|
||||
@ -66,7 +66,7 @@ function App() {
|
||||
})
|
||||
});
|
||||
}
|
||||
}, [isConnected, userPairingId]);
|
||||
}, [isConnected, userPairingId, processes]);
|
||||
|
||||
// Gestionnaire pour afficher la modale de connexion
|
||||
const handleLogin = useCallback(() => {
|
||||
@ -108,21 +108,33 @@ function App() {
|
||||
}, []);
|
||||
|
||||
// Gestionnaire pour soumettre les données du profil
|
||||
const handleProfileSubmit = useCallback((profileData: ProfileData) => {
|
||||
// Ajouter le validator fixe aux données du profil
|
||||
const completeProfileData = {
|
||||
...profileData,
|
||||
validator: '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'
|
||||
};
|
||||
|
||||
MessageBus.getInstance(iframeUrl).createProfile(completeProfileData).then((_profileCreated: ProfileCreated) => {
|
||||
MessageBus.getInstance(iframeUrl).getProcesses().then((processes: any) => {
|
||||
setProcesses(processes);
|
||||
const handleProfileSubmit = useCallback((profileData: ProfileData, validatorId: string | null, ownerId: string | null) => {
|
||||
if (userPairingId !== null) {
|
||||
if (validatorId === null && ownerId === null) {
|
||||
console.error("No validator or owner ID provided");
|
||||
return;
|
||||
}
|
||||
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||
if (validatorId === null) {
|
||||
validatorId = userPairingId;
|
||||
} else if (ownerId === null) {
|
||||
ownerId = userPairingId;
|
||||
}
|
||||
const roles = setDefaultProfileRoles([ownerId!], validatorId!);
|
||||
const profilePrivateFields = ProfilePrivateFields;
|
||||
messageBus.createProfile(profileData, profilePrivateFields, roles).then((_profileCreated: ProfileCreated) => {
|
||||
messageBus.notifyProcessUpdate(_profileCreated.processId, _profileCreated.process.states[0].state_id).then(() => {
|
||||
messageBus.validateState(_profileCreated.processId, _profileCreated.process.states[0].state_id).then((_updatedProcess: any) => {
|
||||
messageBus.getProcesses().then((processes: any) => {
|
||||
setProcesses(processes);
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
setShowProfileModal(false);
|
||||
}, []);
|
||||
setShowProfileModal(false);
|
||||
}
|
||||
}, [userPairingId]);
|
||||
|
||||
// Gestionnaire pour soumettre les données du dossier
|
||||
const handleFolderSubmit = useCallback((folderData: FolderData) => {
|
||||
@ -197,7 +209,7 @@ function App() {
|
||||
<ProfileModal
|
||||
isOpen={showProfileModal}
|
||||
onClose={handleCloseProfileModal}
|
||||
onSubmit={handleProfileSubmit}
|
||||
onSubmit={(profileData: ProfileData, validatorId: string | null, ownerId: string | null) => handleProfileSubmit(profileData, validatorId, ownerId)}
|
||||
/>
|
||||
)}
|
||||
{showFolderModal && (
|
||||
|
@ -165,10 +165,30 @@
|
||||
box-shadow: 0 2px 4px rgba(103, 58, 183, 0.2);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
background-color: #ffebee; /* Light red background */
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
border-left: 4px solid red; /* Left border for emphasis */
|
||||
font-weight: bold;
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.error-message::before {
|
||||
content: "⚠️ "; /* Unicode for warning emoji */
|
||||
}
|
||||
|
||||
/* Styles adaptatifs pour les écrans plus petits */
|
||||
@media (max-width: 768px) {
|
||||
.form-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import type { ProfileData } from '../sdk/models/ProfileData';
|
||||
interface ProfileModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (profileData: ProfileData) => void;
|
||||
onSubmit: (profileData: ProfileData, validatorId: string | null, ownerId: string | null) => void;
|
||||
initialData?: Partial<ProfileData>;
|
||||
}
|
||||
|
||||
@ -23,6 +23,10 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
||||
idDocument: initialData.idDocument || null,
|
||||
idCertified: false,
|
||||
});
|
||||
const [validatorId, setValidatorId] = useState<string | null>(null);
|
||||
const [ownerId, setOwnerId] = useState<string | null>(null);
|
||||
const [isOwnProfile, setIsOwnProfile] = useState<boolean>(false);
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, type, files, value } = e.target;
|
||||
@ -44,7 +48,12 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
onSubmit(profileData);
|
||||
if (!validatorId && !ownerId) {
|
||||
setErrorMessage("Please set either a Validator ID or an Owner ID.");
|
||||
return;
|
||||
}
|
||||
setErrorMessage(null);
|
||||
onSubmit(profileData, validatorId, ownerId);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -176,6 +185,45 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-section">
|
||||
<h3 className="section-title">Profil</h3>
|
||||
<button type="button" onClick={() => setIsOwnProfile(!isOwnProfile)}>
|
||||
{isOwnProfile ? "Je veux faire valider mon profil" : "Je valide le profil d'un utilisateur"}</button>
|
||||
{isOwnProfile ? (
|
||||
<div className="form-field">
|
||||
<label htmlFor="validatorId">ID du validateur</label>
|
||||
<input
|
||||
type="text"
|
||||
id="validatorId"
|
||||
name="validatorId"
|
||||
value={validatorId || ''}
|
||||
onChange={(e) => {
|
||||
setValidatorId(e.target.value);
|
||||
setOwnerId(null);
|
||||
}}
|
||||
placeholder="ID du validateur"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="form-field">
|
||||
<label htmlFor="ownerId">ID de l'utilisateur</label>
|
||||
<input
|
||||
type="text"
|
||||
id="ownerId"
|
||||
name="ownerId"
|
||||
value={ownerId || ''}
|
||||
onChange={(e) => {
|
||||
setOwnerId(e.target.value);
|
||||
setValidatorId(null);
|
||||
}}
|
||||
placeholder="ID de l'utilisateur"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{errorMessage && <div className="error-message">{errorMessage}</div>}
|
||||
|
||||
<div className="form-actions">
|
||||
<button type="button" className="btn-cancel" onClick={onClose}>Annuler</button>
|
||||
<button type="submit" className="btn-submit">Créer le profil</button>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import IframeReference from './IframeReference';
|
||||
import EventBus from './EventBus';
|
||||
import UserStore from './UserStrore';
|
||||
import type { ProfileCreated, ProfileData } from './models/ProfileData';
|
||||
import { isProfileData, type ProfileCreated, type ProfileData } from './models/ProfileData';
|
||||
import { isFolderData, type FolderCreated, type FolderData } from './models/FolderData';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import type { RoleDefinition } from './models/Roles';
|
||||
@ -301,7 +301,7 @@ export default class MessageBus {
|
||||
});
|
||||
}
|
||||
|
||||
public createProfile(profileData: ProfileData): Promise<ProfileCreated> {
|
||||
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();
|
||||
@ -310,16 +310,33 @@ export default class MessageBus {
|
||||
const correlationId = uuidv4();
|
||||
this.initMessageListener(correlationId);
|
||||
|
||||
const unsubscribe = EventBus.getInstance().on('PROFILE_CREATED', (responseId: string, profileCreated: ProfileCreated) => {
|
||||
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_PROFILE_CREATED', (responseId: string, error: string) => {
|
||||
const unsubscribeError = EventBus.getInstance().on('ERROR_PROCESS_CREATED', (responseId: string, error: string) => {
|
||||
if (responseId !== correlationId) {
|
||||
return;
|
||||
}
|
||||
@ -329,9 +346,11 @@ export default class MessageBus {
|
||||
});
|
||||
|
||||
this.sendMessage({
|
||||
type: 'CREATE_PROFILE',
|
||||
profileData,
|
||||
accessToken,
|
||||
type: 'CREATE_PROCESS',
|
||||
processData: profileData,
|
||||
privateFields: profilePrivateData,
|
||||
roles,
|
||||
accessToken
|
||||
});
|
||||
}).catch(console.error);
|
||||
});
|
||||
@ -347,14 +366,13 @@ export default class MessageBus {
|
||||
this.initMessageListener(correlationId);
|
||||
|
||||
const unsubscribe = EventBus.getInstance().on('PROCESS_CREATED', (responseId: string, processCreated: any) => {
|
||||
console.log(processCreated);
|
||||
if (responseId !== correlationId) {
|
||||
return;
|
||||
}
|
||||
unsubscribe();
|
||||
this.destroyMessageListener();
|
||||
// Return value must contain the data commited in the new process
|
||||
const folderData = processCreated.folderCreated;
|
||||
const folderData = processCreated.processData;
|
||||
if (!folderData || !isFolderData(folderData)) reject('Returned invalid process data');
|
||||
if (!processCreated.processId || typeof processCreated.processId !== 'string') reject('Returned invalid process id');
|
||||
// TODO check that process is of type Process
|
||||
|
@ -90,6 +90,11 @@ export interface FolderCreated {
|
||||
|
||||
export function setDefaultFolderRoles(ownerId: string, stakeholdersId: string[], customersId: string[]): Record<string, RoleDefinition> {
|
||||
return {
|
||||
demiurge: {
|
||||
members: [ownerId],
|
||||
validation_rules: [],
|
||||
storages: []
|
||||
},
|
||||
owner: {
|
||||
members: [ownerId],
|
||||
validation_rules: [
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { FileBlob } from "./Data";
|
||||
import { isFileBlob, type FileBlob } from "./Data";
|
||||
import type { RoleDefinition } from "./Roles";
|
||||
|
||||
export interface ProfileData {
|
||||
@ -18,20 +18,36 @@ export function isProfileData(data: any): data is ProfileData{
|
||||
if (typeof data !== 'object' || data === null) return false;
|
||||
|
||||
const requiredStringFields = [
|
||||
'folderNumber',
|
||||
'name',
|
||||
'deedType',
|
||||
'description',
|
||||
'archived_description',
|
||||
'status',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
'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;
|
||||
}
|
||||
|
||||
@ -64,6 +80,11 @@ export interface ProfileCreated {
|
||||
|
||||
export function setDefaultProfileRoles(ownerId: string[], validatorId: string): Record<string, RoleDefinition> {
|
||||
return {
|
||||
demiurge: {
|
||||
members: [...ownerId, validatorId],
|
||||
validation_rules: [],
|
||||
storages: []
|
||||
},
|
||||
owner: {
|
||||
members: ownerId,
|
||||
validation_rules: [
|
||||
|
Loading…
x
Reference in New Issue
Block a user