diff --git a/js/app/components/settings/badge-issuer-panel.tsx b/js/app/components/settings/badge-issuer-panel.tsx index 4307a87ae..7e2d5d4fc 100644 --- a/js/app/components/settings/badge-issuer-panel.tsx +++ b/js/app/components/settings/badge-issuer-panel.tsx @@ -37,10 +37,11 @@ const BADGE_TYPE_OPTIONS: { label: string; value: BadgeType }[] = [ { label: "Event", value: "place.stream.badge.defs#event" }, ]; -type PanelView = "main" | "create"; +type PanelView = "main" | "create" | "issue"; interface BadgeDefItem { uri: string; + cid: string; value: PlaceStreamBadgeDef.Record; } @@ -183,6 +184,9 @@ export function BadgeIssuerPanel() { const [defs, setDefs] = useState([]); const [loadingDefs, setLoadingDefs] = useState(false); + const [selectedDef, setSelectedDef] = useState(null); + const [recipientDid, setRecipientDid] = useState(""); + const [createName, setCreateName] = useState(""); const [createDescription, setCreateDescription] = useState(""); const [createBadgeType, setCreateBadgeType] = useState( @@ -199,7 +203,15 @@ export function BadgeIssuerPanel() { repo: agent.did, limit: 100, }); - setDefs(res.records); + setDefs( + ( + res.records as { + uri: string; + cid: string; + value: PlaceStreamBadgeDef.Record; + }[] + ).map(({ uri, cid, value }) => ({ uri, cid: cid ?? "", value })), + ); } catch (e: any) { toast.show("Failed to load badge definitions", e?.message, { variant: "error", @@ -289,6 +301,85 @@ export function BadgeIssuerPanel() { } }; + const handleIssueBadge = async () => { + if (!agent?.did || !selectedDef || !recipientDid.trim() || working) return; + setWorking(true); + try { + await agent.place.stream.badge.issuance.create( + { repo: agent.did }, + { + did: recipientDid.trim(), + badge: { uri: selectedDef.uri, cid: selectedDef.cid }, + createdAt: new Date().toISOString(), + }, + ); + setLastResult({ + label: `Badge issued to ${recipientDid.trim()}`, + uri: recipientDid.trim(), + }); + setRecipientDid(""); + toast.show("Badge issued", undefined, { variant: "success" }); + setSelectedDef(null); + setView("main"); + } catch (e: any) { + toast.show("Failed to issue badge", e?.message, { variant: "error" }); + } finally { + setWorking(false); + } + }; + + if (view === "issue" && selectedDef) { + return ( + + + + { + setSelectedDef(null); + setView("main"); + }} + /> + Issue Badge + + Issue "{selectedDef.value.name}" to a user by their DID. + + + + + + Recipient DID + + + + + + + + + ); + } + if (view === "create") { return ( @@ -527,12 +618,21 @@ export function BadgeIssuerPanel() { Your Badge Definitions + + Tap a badge to issue it to a user. + {defs.map((def, i) => ( {i > 0 && } - + { + setSelectedDef(def); + setView("issue"); + }} + /> ))}