Skip to content

Commit

Permalink
feat: add header components and attachment sharing (#224)
Browse files Browse the repository at this point in the history
* feat: add header components for plugins

* feat: send and process credentials as attachments when sharing
  • Loading branch information
nickreynolds authored Apr 3, 2024
1 parent 03ccbc1 commit 7433c4b
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 19 deletions.
20 changes: 17 additions & 3 deletions packages/agent-explore/src/plugins/chats/ShareForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import Editor from '@monaco-editor/react';
import { ResponsiveContainer } from '../../components/ResponsiveContainer'
import { v4 } from 'uuid'
import { useNavigate } from 'react-router'
import { computeEntryHash } from '@veramo/utils'


export const ShareForm: React.FC = () => {
const token = theme.useToken()

console.log('here')
const [message, setMessage] = useState<string>(window.localStorage.getItem('bs-post') || '')
const attachment = window.localStorage.getItem('attachment')
const { notification } = App.useApp()
const navigate = useNavigate()

Expand All @@ -26,19 +28,31 @@ console.log('here')
window.localStorage.setItem('bs-post', message)
}, [message])

console.log("attachment: ", attachment)

const handleSend = async (did: string, issuerAgent: TAgent<ICredentialIssuer & IDataStore>) => {
setIsSending(true)
try {
const threadId = v4()
const messageId = v4()

const parsedAttachment = JSON.parse(attachment!)!
const canonicalCredential = parsedAttachment?.proof?.type === 'JwtProof2020' &&
typeof parsedAttachment?.proof?.jwt === 'string'
? parsedAttachment?.proof?.jwt
: parsedAttachment
const threadId = computeEntryHash(canonicalCredential)
const shareMessage = {
type: 'https://didcomm.org/basicmessage/2.0/message',
from: did,
created_time: new Date().getTime(),
to: recepient,
id: threadId,
id: messageId,
thid: threadId,
body: { content: message }
body: { content: message },
attachments: [{
media_type: 'credential+ld+json',
data: { json: JSON.parse(attachment!) }
}]
}
const packedMessage = await issuerAgent.packDIDCommMessage({
message: shareMessage,
Expand Down
1 change: 1 addition & 0 deletions packages/agent-explore/src/plugins/chats/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const getCredentialContextMenuItems = (credential: UniqueVerifiableCreden
}

window.localStorage.setItem('bs-post', embed)
window.localStorage.setItem('attachment', JSON.stringify(credential.verifiableCredential))
navigate(`/chats/share`)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export class SaveMessageHandler extends AbstractMessageHandler {
if (!localMessage) {
console.log('Saving message', message)
await context.agent.dataStoreSaveMessage({ message })
if (message.attachments && message.attachments.length > 0) {
console.log("attachments found")
for (const attachment of message.attachments) {
if (attachment.media_type === 'credential+ld+json') {
const credential = await context.agent.dataStoreSaveVerifiableCredential({ verifiableCredential: attachment.data.json})
console.log("saved attached credential: ", credential)
}
}
}
}
}

Expand Down
54 changes: 38 additions & 16 deletions packages/plugin/src/components/VerifiableCredentialComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ export const VerifiableCredentialComponent = (

console.log({actionComponents})


const headerComponents = React.useMemo(() => {
let headerComponents: React.FC<IVerifiableComponentProps>[] = []
plugins.forEach((plugin) => {
if (plugin.config?.enabled && plugin.getCredentialHeaderComponent) {
const components = plugin.getCredentialHeaderComponent(credential)
if (components) {
headerComponents.push(components)
}
}
})
return headerComponents
}, [plugins])

console.log({headerComponents})

console.log("verifiableCredentail: ", credential)

React.useEffect(() => {
if (verify && !verifyResult && !isVerifying) {
setIsVerifying(true)
Expand Down Expand Up @@ -117,25 +135,29 @@ export const VerifiableCredentialComponent = (
>
<div style={{ justifyItems: 'flex-start', display: 'flex' }}>
<Space direction='horizontal' wrap={true}>
<div>
{!isLoadingProfile && <Avatar src={profile?.picture} size={'small'} />}
{isLoadingProfile && <Skeleton.Avatar active />}
</div>
<IdentifierPopover did={did}>
<Typography.Text ellipsis>
{isLoadingProfile ? shortId(did): profile?.name}
</Typography.Text>
</IdentifierPopover>

<Typography.Text type='secondary'>{formatRelative(
new Date(credential.verifiableCredential.issuanceDate),
new Date()
)}</Typography.Text>
{isVerifying && <Spin size="small"/>}
<div>
{!isLoadingProfile && <Avatar src={profile?.picture} size={'small'} />}
{isLoadingProfile && <Skeleton.Avatar active />}
</div>
<IdentifierPopover did={did}>
<Typography.Text ellipsis>
{isLoadingProfile ? shortId(did): profile?.name}
</Typography.Text>
</IdentifierPopover>

<Typography.Text type='secondary'>{formatRelative(
new Date(credential.verifiableCredential.issuanceDate),
new Date()
)}</Typography.Text>
{isVerifying && <Spin size="small"/>}

{verifyResult?.error && <Tag color="error">{verifyResult.error.message}</Tag>}
{headerComponents.length > 0 && <>
{headerComponents.map((Component, index) => (
React.createElement(Component, { credential })
))}
</>}
</Space>

{isLoadingProfile && <Skeleton.Input style={{ width: 100 }} active />}
</div>

Expand Down
3 changes: 3 additions & 0 deletions packages/plugin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export type IAgentExplorerPlugin = {
/** Returns a react component for a given verifiable credential */
getCredentialComponent?: (credential: UniqueVerifiableCredential) => React.FC<IVerifiableComponentProps> | undefined;

/** Returns a react header component for a given verifiable credential */
getCredentialHeaderComponent?: (credential: UniqueVerifiableCredential) => React.FC<IVerifiableComponentProps> | undefined;

/** Returns a react component that will be displayed in the identifier hover component */
getIdentifierHoverComponent?: () => React.FC<IIdentifierHoverComponentProps>;

Expand Down

0 comments on commit 7433c4b

Please sign in to comment.