Compare commits

...

4 Commits

Author SHA1 Message Date
Sosthene
24a8be727c Update Profile and Folder with FileBlob 2025-06-13 16:13:59 +02:00
Sosthene
f9f9739cbd Add FileBlob type 2025-06-13 16:12:28 +02:00
Sosthene
a71dc88407 Display all commitments for each process 2025-06-13 16:12:13 +02:00
Sosthene
512d981b1b ProcessesViewer display the filtered number of processes 2025-06-13 16:11:48 +02:00
5 changed files with 150 additions and 18 deletions

View File

@ -4,6 +4,7 @@ import './ProcessesViewer.css';
interface BlockState { interface BlockState {
commited_in: string; commited_in: string;
state_id: string; state_id: string;
pcd_commitment: Record<string, string>;
public_data: { public_data: {
memberPublicName?: string | number[]; memberPublicName?: string | number[];
pairedAddresses?: string[] | number[]; pairedAddresses?: string[] | number[];
@ -96,7 +97,11 @@ function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) {
<button onClick = {handleFilterClick}> <button onClick = {handleFilterClick}>
{isFiltered ? 'Show All Processes' : 'Filter Processes'} {isFiltered ? 'Show All Processes' : 'Filter Processes'}
</button> </button>
<p className="block-count">{Object.keys(processes).length} processus disponible(s)</p> <p className="block-count">
{isFiltered
? Object.keys(processes).filter(processId => myProcesses.includes(processId)).length
: Object.keys(processes).length} processus disponible(s)
</p>
<div className="block-list"> <div className="block-list">
{Object.entries(processes).map(([processId, process]) => { {Object.entries(processes).map(([processId, process]) => {
@ -124,19 +129,29 @@ function ProcessesViewer({ processes, myProcesses }: ProcessesViewerProps) {
{isExpanded && ( {isExpanded && (
<div className="block-details"> <div className="block-details">
<div className="block-complete-id"> <div className="block-complete-id">
<strong>ID complet:</strong> {processId} <strong>Process ID:</strong> {processId}
</div> </div>
{process.states.map((state, index) => { {process.states.map((state, index) => {
if (index === stateCount - 1) return null; if (index === stateCount) return null;
return ( return (
<div key={`${processId}-state-${index}`} className="state-item"> <div key={`${processId}-state-${index}`} className="state-item">
<h4>État {index + 1}</h4> <h4>État {index + 1}</h4>
<div className="state-detail"> <div className="state-detail">
<strong>State ID:</strong> {state.state_id} <strong>TransactionId:</strong> {state.commited_in}
</div> </div>
<div className="state-detail"> <div className="state-detail">
<strong>Commited dans:</strong> {state.commited_in} <strong>Empreinte totale de l'état:</strong> {state.state_id}
</div>
<div className="state-detail">
<strong>Empreinte par information:</strong>
<ul>
{Object.entries(state.pcd_commitment).map(([key, value]) => (
<div key={key}>
<strong>{key}:</strong> {value}
</div>
))}
</ul>
</div> </div>
<div className="state-public-data"> <div className="state-public-data">

View File

@ -20,15 +20,26 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
postalCode: initialData.postalCode || '', postalCode: initialData.postalCode || '',
city: initialData.city || '', city: initialData.city || '',
country: initialData.country || '', country: initialData.country || '',
idDocument: initialData.idDocument || '', idDocument: initialData.idDocument || null,
idCertified: false,
}); });
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target; const { name, type, files, value } = e.target;
setProfileData(prev => ({
...prev, if (type === 'file' && files) {
[name]: value // Assuming you want to handle a single file
})); const file = files[0];
setProfileData(prev => ({
...prev,
[name]: file
}));
} else {
setProfileData(prev => ({
...prev,
[name]: value
}));
}
}; };
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
@ -157,12 +168,10 @@ function ProfileModal({ isOpen, onClose, onSubmit, initialData = {} }: ProfileMo
<div className="form-field"> <div className="form-field">
<label htmlFor="idDocument">Document d'identité&nbsp;<span className="optional">(optionnel)</span></label> <label htmlFor="idDocument">Document d'identité&nbsp;<span className="optional">(optionnel)</span></label>
<input <input
type="text" type="file"
id="idDocument" id="idDocument"
name="idDocument" name="idDocument"
value={profileData.idDocument || ''}
onChange={handleChange} onChange={handleChange}
placeholder="Numéro de document"
/> />
</div> </div>
</div> </div>

15
src/sdk/models/Data.ts Normal file
View File

@ -0,0 +1,15 @@
export interface FileBlob {
type: string,
data: Uint8Array
};
export function isFileBlob(data: any): data is FileBlob {
return (
typeof data === 'object' &&
data !== null &&
'type' in data &&
typeof data.type === 'string' &&
'data' in data &&
data.data instanceof Uint8Array
);
}

View File

@ -1,3 +1,4 @@
import { isFileBlob, type FileBlob } from "./Data";
import type { RoleDefinition } from "./Roles"; import type { RoleDefinition } from "./Roles";
export interface FolderData { export interface FolderData {
@ -10,7 +11,7 @@ export interface FolderData {
created_at: string; created_at: string;
updated_at: string; updated_at: string;
customers: string[]; customers: string[];
documents: string[]; documents: FileBlob[];
motes: string[]; motes: string[];
stakeholders: string[]; stakeholders: string[];
} }
@ -35,7 +36,6 @@ export function isFolderData(data: any): data is FolderData {
const requiredArrayFields = [ const requiredArrayFields = [
'customers', 'customers',
'documents',
'motes', 'motes',
'stakeholders' 'stakeholders'
]; ];
@ -46,6 +46,15 @@ export function isFolderData(data: any): data is FolderData {
} }
} }
const requiredFileBlobArrayFields = [
'documents',
];
for (const field of requiredFileBlobArrayFields) {
if (!Array.isArray(data[field])) return false;
if (data[field].length > 0 && !data[field].every(isFileBlob)) return false;
}
return true; return true;
} }

View File

@ -1,3 +1,6 @@
import type { FileBlob } from "./Data";
import type { RoleDefinition } from "./Roles";
export interface ProfileData { export interface ProfileData {
name: string; name: string;
surname: string; surname: string;
@ -7,11 +10,92 @@ export interface ProfileData {
postalCode: string; postalCode: string;
city: string; city: string;
country: string; country: string;
idDocument?: string; idDocument: FileBlob | null;
idCertified: boolean;
} }
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'
];
for (const field of requiredStringFields) {
if (typeof data[field] !== 'string') 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 { export interface ProfileCreated {
processId: string, processId: string,
process: any, // Actually Process process: any, // Process
profileData: ProfileData, profileData: ProfileData,
} }
export function setDefaultProfileRoles(ownerId: string[], validatorId: string): Record<string, RoleDefinition> {
return {
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: []
}
}
};