Skip to content

Commit

Permalink
✨ Allow adding account to workspace from handle (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
foysalit committed Sep 11, 2024
1 parent ce30b8a commit 56f85a8
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 22 deletions.
93 changes: 71 additions & 22 deletions components/workspace/ItemCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ActionButton } from '@/common/buttons'
import { PlusIcon, XMarkIcon } from '@heroicons/react/20/solid'
import { toast } from 'react-toastify'
import { buildItemsSummary, groupSubjects } from './utils'
import { getDidFromHandleInBatch } from '@/lib/identity'
import { ArrowPathIcon } from '@heroicons/react/24/solid'

interface WorkspaceItemCreatorProps {
onCancel?: () => void
Expand All @@ -16,32 +18,69 @@ const WorkspaceItemCreator: React.FC<WorkspaceItemCreatorProps> = ({
size = 'lg',
}) => {
const addItemsMutation = useWorkspaceAddItemsMutation()
const [isAdding, setIsAdding] = React.useState(false)

const handleSubmit = (
const handleSubmit = async (
event: React.FormEvent<HTMLFormElement> & { target: HTMLFormElement },
) => {
event.preventDefault()
event.stopPropagation()
const formData = new FormData(event.currentTarget)
const items = formData.get('items') as string
const itemList = items
.split(',')
.map((item) => item.trim())
.filter((item) => item.startsWith('did:') || item.startsWith('at://'))
const groupedItems = groupSubjects(itemList)
setIsAdding(true)

addItemsMutation.mutate(itemList, {
onSuccess: () => {
const addedItemsSummary = buildItemsSummary(groupedItems)
toast.success(`Added ${addedItemsSummary} to the list.`)
event.target.reset()
onCancel?.()
},
onError: () => {
toast.error('Failed to add items to the list.')
},
})
return false
try {
const formData = new FormData(event.currentTarget)
const items = formData.get('items') as string
const isPossiblyHandle = (item) => item.includes('.')
const itemList = items
.split(',')
.map((item) => item.trim())
.filter(
(item) =>
item.startsWith('did:') ||
item.startsWith('at://') ||
isPossiblyHandle(item),
)

const handleList = itemList.filter(isPossiblyHandle)

// If there are handles in the list, we need to resolve them to DIDs and replace the handles with dids before placing them in the workspace
if (handleList.length > 0) {
const handleToDid = await getDidFromHandleInBatch(handleList)
Object.keys(handleToDid).forEach((handle) => {
// If we couldn't find the did, we don't want to replace the handle in the list
if (handleToDid[handle] === null) {
return
}
const handleIndex = itemList.indexOf(handle)
if (handleIndex !== -1) {
itemList[handleIndex] = handleToDid[handle]
}
})
}

const groupedItems = groupSubjects(itemList)

await addItemsMutation.mutateAsync(itemList, {
onSuccess: () => {
const addedItemsSummary = buildItemsSummary(groupedItems)
toast.success(`Added ${addedItemsSummary} to workspace.`)
event.target.reset()
onCancel?.()
},
onError: () => {
toast.error('Failed to add items to workspace.')
},
})

setIsAdding(false)
return false
} catch (error) {
console.error(error)
setIsAdding(false)
toast.error(
`Failed to add items to workspace. ${(error as Error).message}`,
)
}
}

return (
Expand All @@ -51,6 +90,7 @@ const WorkspaceItemCreator: React.FC<WorkspaceItemCreatorProps> = ({
>
<Input
autoFocus
disabled={isAdding}
name="items"
onKeyDown={(e) => {
if (e.key === 'Escape' && !!onCancel) {
Expand All @@ -61,8 +101,17 @@ const WorkspaceItemCreator: React.FC<WorkspaceItemCreatorProps> = ({
placeholder="Enter DID/AT-URI items separated by commas"
className={`block ${size === 'sm' ? 'p-1' : 'p-2'} w-full`}
/>
<ActionButton type="submit" appearance="outlined" size={size}>
<PlusIcon className={size === 'lg' ? 'h-5 w-5' : 'h-3 w-3'} />
<ActionButton
type="submit"
appearance="outlined"
size={size}
disabled={isAdding}
>
{isAdding ? (
<ArrowPathIcon className={size === 'lg' ? 'h-5 w-5' : 'h-3 w-3'} />
) : (
<PlusIcon className={size === 'lg' ? 'h-5 w-5' : 'h-3 w-3'} />
)}
</ActionButton>
{!!onCancel && (
<ActionButton
Expand Down
16 changes: 16 additions & 0 deletions lib/identity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { globalAgent } from './client'
import { PLC_DIRECTORY_URL } from './constants'
import { chunkArray } from './util'

export const getDidFromHandle = async (
handle: string,
Expand All @@ -12,6 +13,21 @@ export const getDidFromHandle = async (
}
}

export const getDidFromHandleInBatch = async (handles: string[]) => {
const handleToDid: Record<string, string | null> = {}

for (const handleChunk of chunkArray(handles, 50)) {
await Promise.all(
handleChunk.map(async (handle) => {
const did = await getDidFromHandle(handle)
handleToDid[handle] = did
}),
)
}

return handleToDid
}

export const resolveDidDocData = async function (
did: string,
signal?: AbortSignal,
Expand Down

0 comments on commit 56f85a8

Please sign in to comment.