Skip to content

Commit 4cacd81

Browse files
pheobeayojoelamouche
authored andcommitted
feat: added a section with the badges issued by that profile
1 parent fc2163b commit 4cacd81

6 files changed

Lines changed: 180 additions & 49 deletions

File tree

frontend/.astro/data-store.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.13.7","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\",\"entrypoint\":\"astro/assets/endpoint/node\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false},\"legacy\":{\"collections\":false},\"session\":{\"driver\":\"fs-lite\",\"options\":{\"base\":\"/Users/theodoreabitbol/Desktop/TheGuildGenesis/frontend/node_modules/.astro/sessions\"}}}"]
1+
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.14.1","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\",\"entrypoint\":\"astro/assets/endpoint/node\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false},\"legacy\":{\"collections\":false},\"session\":{\"driver\":\"fs-lite\",\"options\":{\"base\":\"/home/phoebe/TheGuildGenesis/frontend/node_modules/.astro/sessions\"}}}"]

frontend/.astro/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"_variables": {
3-
"lastUpdateCheck": 1758201525305
3+
"lastUpdateCheck": 1759589860759
44
},
55
"eslint.validate": [
66
"javascript",

frontend/package-lock.json

Lines changed: 58 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"@tanstack/react-router": "^1.131.36",
3333
"@types/react": "^19.1.12",
3434
"@types/react-dom": "^19.1.9",
35-
"astro": "^5.13.7",
35+
"astro": "^5.14.1",
3636
"class-variance-authority": "^0.7.1",
3737
"clsx": "^2.1.1",
3838
"dotenv": "^17.2.2",

frontend/src/components/pages/ProfilePage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AppWrapper } from "@/components/AppWrapper";
22
import ProfileHeader from "@/components/profiles/profile-page/ProfileHeader";
33
import ProfileActions from "@/components/profiles/profile-page/ProfileActions";
44
import ProfileAttestations from "@/components/profiles/profile-page/ProfileAttestations";
5+
import ProfileIssuedAttestations from "../profiles/profile-page/ProfileIssuedAttestations";
56

67
type Props = { address?: string };
78

@@ -14,6 +15,8 @@ export default function ProfilePage({ address }: Props) {
1415
<ProfileActions address={address || ""} />
1516

1617
<ProfileAttestations address={address || ""} />
18+
19+
<ProfileIssuedAttestations address={address || ""} />
1720
</section>
1821
</AppWrapper>
1922
);
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { Send, Badge } from "lucide-react";
2+
import { useGetAttestations } from "@/hooks/attestations/use-get-attestations";
3+
import { useMemo } from "react";
4+
import {
5+
Accordion,
6+
AccordionContent,
7+
AccordionItem,
8+
AccordionTrigger,
9+
} from "@/components/ui/accordion";
10+
import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
11+
12+
export function ProfileIssuedAttestations({ address }: { address: string }) {
13+
const attestationsQuery = useGetAttestations();
14+
const profilesQuery = useGetProfiles();
15+
16+
const issuedAttestations = useMemo(() => {
17+
const list = attestationsQuery.data ?? [];
18+
const filtered = list.filter(
19+
(a) => a.issuer.toLowerCase() === (address || "").toLowerCase()
20+
);
21+
return filtered.map((a, i) => ({
22+
id: String(i),
23+
badgeName: a.badgeName,
24+
justification: a.attestationJustification,
25+
recipient: a.recipient,
26+
}));
27+
}, [attestationsQuery.data, address]);
28+
29+
const profileNameByAddress = useMemo(() => {
30+
const map = new Map<string, string>();
31+
const list = profilesQuery.data ?? [];
32+
for (const p of list) {
33+
if (p.address) map.set(p.address.toLowerCase(), p.name || "");
34+
}
35+
return map;
36+
}, [profilesQuery.data]);
37+
38+
const grouped = useMemo(() => {
39+
const map = new Map<
40+
string,
41+
{ id: string; recipient: string; justification: string }[]
42+
>();
43+
for (const a of issuedAttestations) {
44+
const arr = map.get(a.badgeName) ?? [];
45+
arr.push({ id: a.id, recipient: a.recipient, justification: a.justification });
46+
map.set(a.badgeName, arr);
47+
}
48+
return Array.from(map.entries()).map(([badgeName, items]) => ({
49+
badgeName,
50+
items,
51+
}));
52+
}, [issuedAttestations]);
53+
54+
return (
55+
<section className="mt-10">
56+
<h2 className="text-lg font-medium mb-4 flex items-center gap-2">
57+
<Send className="h-5 w-5" /> Issued Attestations ({issuedAttestations.length})
58+
</h2>
59+
{issuedAttestations.length === 0 ? (
60+
<p className="text-sm text-gray-600">No attestations issued yet.</p>
61+
) : (
62+
<Accordion type="multiple" className="w-full space-y-2">
63+
{grouped.map(({ badgeName, items }, idx) => (
64+
<AccordionItem
65+
key={badgeName || idx}
66+
value={badgeName || String(idx)}
67+
>
68+
<AccordionTrigger>
69+
<div className="flex items-center gap-2">
70+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
71+
<Badge className="h-3 w-3 mr-1" />{" "}
72+
{badgeName || "(unnamed)"}
73+
</span>
74+
<span className="text-sm text-gray-600">
75+
({items.length})
76+
</span>
77+
</div>
78+
</AccordionTrigger>
79+
<AccordionContent>
80+
<ul className="space-y-3">
81+
{items.map((it) => (
82+
<li
83+
key={it.id}
84+
className="border rounded-lg p-4 flex items-start justify-between"
85+
>
86+
<div className="flex items-start gap-3">
87+
<div>
88+
<p className="text-sm text-gray-800">
89+
{it.justification}
90+
</p>
91+
<p className="text-xs text-gray-500 mt-1">
92+
Issued to{" "}
93+
<a
94+
className="text-indigo-600 hover:underline"
95+
href={`/profiles/${it.recipient}`}
96+
>
97+
{profileNameByAddress.get(
98+
it.recipient.toLowerCase()
99+
) || `${it.recipient.slice(0, 6)}...${it.recipient.slice(-4)}`}
100+
</a>
101+
</p>
102+
</div>
103+
</div>
104+
</li>
105+
))}
106+
</ul>
107+
</AccordionContent>
108+
</AccordionItem>
109+
))}
110+
</Accordion>
111+
)}
112+
</section>
113+
);
114+
}
115+
116+
export default ProfileIssuedAttestations;

0 commit comments

Comments
 (0)