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 Iframe from './sdk/Iframe'
|
||||||
import BlockchainViewer from './components/ProcessesViewer';
|
import BlockchainViewer from './components/ProcessesViewer';
|
||||||
import FolderModal from './components/FolderModal';
|
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'
|
import { FolderPrivateFields, setDefaultFolderRoles, type FolderCreated, type FolderData } from './sdk/models/FolderData'
|
||||||
|
|
||||||
const iframeUrl = 'https://dev3.4nkweb.com'
|
const iframeUrl = 'https://dev3.4nkweb.com'
|
||||||
@ -66,7 +66,7 @@ function App() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isConnected, userPairingId]);
|
}, [isConnected, userPairingId, processes]);
|
||||||
|
|
||||||
// Gestionnaire pour afficher la modale de connexion
|
// Gestionnaire pour afficher la modale de connexion
|
||||||
const handleLogin = useCallback(() => {
|
const handleLogin = useCallback(() => {
|
||||||
@ -108,21 +108,33 @@ function App() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Gestionnaire pour soumettre les données du profil
|
// Gestionnaire pour soumettre les données du profil
|
||||||
const handleProfileSubmit = useCallback((profileData: ProfileData) => {
|
const handleProfileSubmit = useCallback((profileData: ProfileData, validatorId: string | null, ownerId: string | null) => {
|
||||||
// Ajouter le validator fixe aux données du profil
|
if (userPairingId !== null) {
|
||||||
const completeProfileData = {
|
if (validatorId === null && ownerId === null) {
|
||||||
...profileData,
|
console.error("No validator or owner ID provided");
|
||||||
validator: '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'
|
return;
|
||||||
};
|
}
|
||||||
|
const messageBus = MessageBus.getInstance(iframeUrl);
|
||||||
MessageBus.getInstance(iframeUrl).createProfile(completeProfileData).then((_profileCreated: ProfileCreated) => {
|
if (validatorId === null) {
|
||||||
MessageBus.getInstance(iframeUrl).getProcesses().then((processes: any) => {
|
validatorId = userPairingId;
|
||||||
setProcesses(processes);
|
} 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
|
// Gestionnaire pour soumettre les données du dossier
|
||||||
const handleFolderSubmit = useCallback((folderData: FolderData) => {
|
const handleFolderSubmit = useCallback((folderData: FolderData) => {
|
||||||
@ -197,7 +209,7 @@ function App() {
|
|||||||
<ProfileModal
|
<ProfileModal
|
||||||
isOpen={showProfileModal}
|
isOpen={showProfileModal}
|
||||||
onClose={handleCloseProfileModal}
|
onClose={handleCloseProfileModal}
|
||||||
onSubmit={handleProfileSubmit}
|
onSubmit={(profileData: ProfileData, validatorId: string | null, ownerId: string | null) => handleProfileSubmit(profileData, validatorId, ownerId)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showFolderModal && (
|
{showFolderModal && (
|
||||||
|
@ -165,10 +165,30 @@
|
|||||||
box-shadow: 0 2px 4px rgba(103, 58, 183, 0.2);
|
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 */
|
/* Styles adaptatifs pour les écrans plus petits */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.form-row {
|
.form-row {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ import type { ProfileData } from '../sdk/models/ProfileData';
|
|||||||
interface ProfileModalProps {
|
interface ProfileModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSubmit: (profileData: ProfileData) => void;
|
onSubmit: (profileData: ProfileData, validatorId: string | null, ownerId: string | null) => void;
|
||||||
initialData?: Partial<ProfileData>;
|
initialData?: Partial<ProfileData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +23,10 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
|||||||
idDocument: initialData.idDocument || null,
|
idDocument: initialData.idDocument || null,
|
||||||
idCertified: false,
|
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 handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, type, files, value } = e.target;
|
const { name, type, files, value } = e.target;
|
||||||
@ -44,7 +48,12 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
|||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
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 (
|
return (
|
||||||
@ -176,6 +185,45 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<div className="form-actions">
|
||||||
<button type="button" className="btn-cancel" onClick={onClose}>Annuler</button>
|
<button type="button" className="btn-cancel" onClick={onClose}>Annuler</button>
|
||||||
<button type="submit" className="btn-submit">Créer le profil</button>
|
<button type="submit" className="btn-submit">Créer le profil</button>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import IframeReference from './IframeReference';
|
import IframeReference from './IframeReference';
|
||||||
import EventBus from './EventBus';
|
import EventBus from './EventBus';
|
||||||
import UserStore from './UserStrore';
|
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 { 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';
|
||||||
@ -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) => {
|
return new Promise<ProfileCreated>((resolve: (profileCreated: ProfileCreated) => void, reject: (error: string) => void) => {
|
||||||
this.checkToken().then(() => {
|
this.checkToken().then(() => {
|
||||||
const userStore = UserStore.getInstance();
|
const userStore = UserStore.getInstance();
|
||||||
@ -310,16 +310,33 @@ export default class MessageBus {
|
|||||||
const correlationId = uuidv4();
|
const correlationId = uuidv4();
|
||||||
this.initMessageListener(correlationId);
|
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) {
|
if (responseId !== correlationId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
this.destroyMessageListener();
|
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);
|
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) {
|
if (responseId !== correlationId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -329,9 +346,11 @@ export default class MessageBus {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
type: 'CREATE_PROFILE',
|
type: 'CREATE_PROCESS',
|
||||||
profileData,
|
processData: profileData,
|
||||||
accessToken,
|
privateFields: profilePrivateData,
|
||||||
|
roles,
|
||||||
|
accessToken
|
||||||
});
|
});
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
});
|
});
|
||||||
@ -347,14 +366,13 @@ export default class MessageBus {
|
|||||||
this.initMessageListener(correlationId);
|
this.initMessageListener(correlationId);
|
||||||
|
|
||||||
const unsubscribe = EventBus.getInstance().on('PROCESS_CREATED', (responseId: string, processCreated: any) => {
|
const unsubscribe = EventBus.getInstance().on('PROCESS_CREATED', (responseId: string, processCreated: any) => {
|
||||||
console.log(processCreated);
|
|
||||||
if (responseId !== correlationId) {
|
if (responseId !== correlationId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
this.destroyMessageListener();
|
this.destroyMessageListener();
|
||||||
// Return value must contain the data commited in the new process
|
// 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 (!folderData || !isFolderData(folderData)) reject('Returned invalid process data');
|
||||||
if (!processCreated.processId || typeof processCreated.processId !== 'string') reject('Returned invalid process id');
|
if (!processCreated.processId || typeof processCreated.processId !== 'string') reject('Returned invalid process id');
|
||||||
// TODO check that process is of type Process
|
// 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> {
|
export function setDefaultFolderRoles(ownerId: string, stakeholdersId: string[], customersId: string[]): Record<string, RoleDefinition> {
|
||||||
return {
|
return {
|
||||||
|
demiurge: {
|
||||||
|
members: [ownerId],
|
||||||
|
validation_rules: [],
|
||||||
|
storages: []
|
||||||
|
},
|
||||||
owner: {
|
owner: {
|
||||||
members: [ownerId],
|
members: [ownerId],
|
||||||
validation_rules: [
|
validation_rules: [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { FileBlob } from "./Data";
|
import { isFileBlob, type FileBlob } from "./Data";
|
||||||
import type { RoleDefinition } from "./Roles";
|
import type { RoleDefinition } from "./Roles";
|
||||||
|
|
||||||
export interface ProfileData {
|
export interface ProfileData {
|
||||||
@ -18,20 +18,36 @@ export function isProfileData(data: any): data is ProfileData{
|
|||||||
if (typeof data !== 'object' || data === null) return false;
|
if (typeof data !== 'object' || data === null) return false;
|
||||||
|
|
||||||
const requiredStringFields = [
|
const requiredStringFields = [
|
||||||
'folderNumber',
|
|
||||||
'name',
|
'name',
|
||||||
'deedType',
|
'surname',
|
||||||
'description',
|
'email',
|
||||||
'archived_description',
|
'phone',
|
||||||
'status',
|
'address',
|
||||||
'created_at',
|
'postalCode',
|
||||||
'updated_at'
|
'city',
|
||||||
|
'country',
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const field of requiredStringFields) {
|
for (const field of requiredStringFields) {
|
||||||
if (typeof data[field] !== 'string') return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +80,11 @@ export interface ProfileCreated {
|
|||||||
|
|
||||||
export function setDefaultProfileRoles(ownerId: string[], validatorId: string): Record<string, RoleDefinition> {
|
export function setDefaultProfileRoles(ownerId: string[], validatorId: string): Record<string, RoleDefinition> {
|
||||||
return {
|
return {
|
||||||
|
demiurge: {
|
||||||
|
members: [...ownerId, validatorId],
|
||||||
|
validation_rules: [],
|
||||||
|
storages: []
|
||||||
|
},
|
||||||
owner: {
|
owner: {
|
||||||
members: ownerId,
|
members: ownerId,
|
||||||
validation_rules: [
|
validation_rules: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user