Created
September 28, 2023 15:17
-
-
Save leordev/8d6aa6e418673b9e07f203c0461de364 to your computer and use it in GitHub Desktop.
web5 on client side only
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useContext, useState, updateState, setState, useEffect } from "react"; | |
import AppContext from "../components/AppContext"; | |
import { useRouter } from "next/router"; | |
import { Web5 } from "@web5/api"; | |
import Ajv from "ajv"; | |
/*import { webcrypto } from "node:crypto"; | |
// @ts-ignore | |
if (!globalThis.crypto) globalThis.crypto = webcrypto;*/ | |
//import * as dotenv from 'dotenv'; | |
//dotenv.config( | |
const PROTOCOL_ID = 'http://selfkey.org/protocols/credentialSharing'; | |
const CREDENTIAL_SCHEMA = { | |
"type": "object", | |
"properties": { | |
"@context": { | |
"type": "array", | |
"items": [ | |
{ | |
"type": "string" | |
}, | |
{ | |
"type": "string" | |
} | |
], | |
"minItems": 1, | |
}, | |
"id": { | |
"type": "string" | |
}, | |
"type": { | |
"type": "array", | |
"items": [ | |
{ | |
"type": "string" | |
}, | |
{ | |
"type": "string" | |
} | |
], | |
"minItems": 1 | |
}, | |
"issuer": { | |
"type": "string" | |
}, | |
"validFrom": { | |
"type": "string" | |
}, | |
"credentialSubject": { | |
"type": "object", | |
"properties": { | |
"id": { | |
"type": "string" | |
}, | |
"degree": { | |
"type": "object", | |
"properties": { | |
"type": { | |
"type": "string" | |
}, | |
"name": { | |
"type": "string" | |
} | |
}, | |
"required": [ | |
"type", | |
"name" | |
] | |
} | |
}, | |
"required": [ | |
"id", | |
"degree" | |
] | |
}, | |
"proof": { | |
"type": "object", | |
"properties": { | |
"type": { | |
"type": "string" | |
}, | |
"created": { | |
"type": "string" | |
}, | |
"verificationMethod": { | |
"type": "string" | |
}, | |
"proofPurpose": { | |
"type": "string" | |
}, | |
"proofValue": { | |
"type": "string" | |
} | |
}, | |
"required": [ | |
"type", | |
"created", | |
"verificationMethod", | |
"proofPurpose", | |
"proofValue" | |
] | |
} | |
}, | |
"required": [ | |
"@context", | |
"id", | |
"type", | |
"issuer", | |
"validFrom", | |
"credentialSubject", | |
"proof" | |
] | |
}; | |
function Header(props) { | |
return(<h1>{props.title}</h1>); | |
} | |
function CredentialTable(props) { | |
const [refreshState, setRefreshState] = useState(0); | |
const context = useContext(AppContext); | |
const router = useRouter(); | |
function viewCredential(index) { | |
var document = { | |
//name: props.names[index], | |
}; | |
context.setSession({document: document}); | |
router.push('/edit/'); | |
} | |
function deleteCredential(did, recordId) { | |
console.log("deleteCredential id: ", recordId); | |
/*web5.dwn.records.delete({ | |
from: did, | |
message: { | |
recordId: recordId, | |
} | |
})*/ | |
refresh(); | |
} | |
function refresh() { | |
console.log("CredentialTable refresh"); | |
setRefreshState(refreshState + 1); | |
// empty arrays? | |
} | |
return ( | |
<div onLoad={refresh}> | |
<p>My credentials:</p> | |
<table> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Description</th> | |
<th></th> | |
<th></th> | |
</tr> | |
</thead> | |
<tbody> | |
{ | |
props.recordIds.map((value, i) => { | |
return( | |
<tr key={i}> | |
<td> | |
{props.names[i]} | |
</td> | |
<td> | |
{props.descriptions[i]} | |
</td> | |
<td> | |
<button onClick={() => viewCredential(i)}>View</button> | |
</td> | |
<td> | |
<button onClick={() => deleteCredential(props.recordIds[i])}>Delete</button> | |
</td> | |
</tr>) | |
})} | |
</tbody> | |
</table> | |
</div> | |
); | |
} | |
export default function HomePage() { | |
const [file, setFile] = useState(null); | |
const [dataArray, setDataArray] = useState(new Array()); | |
const [refreshState, setRefreshState] = useState(""); | |
const [submitDisabled, setSubmitDisabled] = useState("false"); | |
const [recordIds, setRecordIds] = useState([]); | |
const [names, setNames] = useState([]); | |
const [descriptions, setDescriptions] = useState([]); | |
const [credentials, setCredentials] = useState([]); | |
const [web5, setWeb5] = useState(undefined); | |
const [did, setDid] = useState(undefined); | |
const context = useContext(AppContext); | |
const router = useRouter(); | |
useEffect(() => { | |
const fetchData = async () => { | |
// Instantianting Web5 on the client ONLY! | |
let { web5, did: myDid } = await Web5.connect() | |
setWeb5(web5) | |
setDid(myDid) | |
/*const { records } = await web5.dwn.records.query({ | |
//from: did, // store did in session? | |
message: { | |
filter: { | |
protocol: PROTOCOL_ID, | |
schema: CREDENTIAL_SCHEMA, | |
dataFormat: "application/json", | |
}, | |
}, | |
});*/ | |
/*for(var i = 0; i < records.length; i++) { | |
const record = records[i]; | |
recordIds[i] = record.data.id;//; | |
names[i] = record.data.name;//; | |
descriptions[i] = record.data.description; | |
credentials[i] = record.data; | |
}*/ | |
setRefreshState("done"); // check if necessary | |
} | |
setSubmitDisabled("false"); | |
fetchData().catch(console.error); | |
}, []); | |
function retrieveFile(e) { | |
const data = e.target.files[0]; | |
try{ | |
const reader = new window.FileReader(); | |
reader.readAsArrayBuffer(data); | |
reader.onloadend = () => { | |
const file = Buffer(reader.result); | |
const jsonData = JSON.parse(file.toString()); | |
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} | |
const validate = ajv.compile(CREDENTIAL_SCHEMA); | |
const valid = validate(jsonData); | |
if (!valid) { | |
setSubmitDisabled("true"); | |
console.log(validate.errors); | |
} else { | |
setSubmitDisabled("false"); | |
console.log("schema check passed"); | |
} | |
setFile(file); | |
}; | |
} catch (error) { | |
console.log(error); | |
} | |
e.preventDefault(); | |
} | |
async function handleSubmit(e) { | |
/*if (web5 == undefined) { | |
{ web5, did: myDid } = await Web5.connect(); | |
}*/ | |
e.preventDefault(); | |
try { | |
const f = file.toString(); | |
const data = JSON.parse(f); | |
const { record } = await web5.dwn.records.create({ | |
store: false, | |
data: data, | |
message: { | |
dataFormat: "text/plain", | |
//protocol: PROTOCOL_ID, | |
//schema: CREDENTIAL_SCHEMA, | |
}, | |
}); | |
if (record) | |
console.log("new record created: ", record); | |
refresh(); | |
} catch (error) { | |
console.log(error.message); | |
} | |
} | |
function refresh() { | |
console.log("Homepage refresh"); | |
setRefreshState(refreshState == 0 ? 1 : 0); | |
} | |
return ( | |
<div onLoad={refresh}> | |
<Header title="Lit Protocol PoC" /> | |
<br></br> | |
<CredentialTable recordIds={recordIds} names={names} descriptions={descriptions} credentials={credentials}></CredentialTable> | |
<p>Submit a credential to store on Decentralized Web Node</p> | |
<form onSubmit={handleSubmit}> | |
<table> | |
<tbody> | |
<tr> | |
<td><label>File:</label></td> | |
<td><input type="file" onChange={retrieveFile} required /></td> | |
</tr> | |
<tr> | |
<td><label>Name: </label></td> | |
<td><input id="dataName" type="text" /></td> | |
</tr> | |
<tr> | |
<td><label>Description: </label></td> | |
<td><input id="dataDescription" type="text" /></td> | |
</tr> | |
<tr> | |
<td><button /*disabled={{ submitDisabled }}*/ type="submit" className="button">Submit</button></td> | |
<td></td> | |
</tr> | |
</tbody> | |
</table> | |
</form> | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment