From a634bd39c52fcc26528f1f9947123d6bc13145a7 Mon Sep 17 00:00:00 2001
From: pheobeayo
Date: Mon, 6 Oct 2025 17:54:56 +0100
Subject: [PATCH 1/6] feature: added a github handle to profile in frontend
---
.../action-buttons/EditProfileDialog.tsx | 79 +++++++++++++------
.../profiles/profile-page/ProfileHeader.tsx | 22 +++++-
frontend/src/lib/types/api.d.ts | 7 +-
frontend/src/lib/types/profiles.d.ts | 3 +-
4 files changed, 83 insertions(+), 28 deletions(-)
diff --git a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
index f4619c6..9c41ba6 100644
--- a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
+++ b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
@@ -28,44 +28,56 @@ interface EditProfileDialogProps {
address: string;
name?: string;
description?: string;
+ githubHandle?: string;
children: React.ReactNode;
}
+const formSchema = z.object({
+ name: z
+ .string()
+ .min(2, { message: "Name must be at least 2 characters." }),
+ description: z.string().optional(),
+ githubHandle: z.string().optional(),
+});
+
+type FormValues = z.infer;
+
export function EditProfileDialog({
address,
name,
description,
+ githubHandle,
children,
}: EditProfileDialogProps) {
const [open, setOpen] = useState(false);
const updateProfile = useUpdateProfile();
const queryClient = useQueryClient();
- const form = useForm<{
- name: string;
- description?: string;
- }>({
- resolver: zodResolver(
- z.object({
- name: z
- .string()
- .min(2, { message: "Name must be at least 2 characters." }),
- description: z.string().optional(),
- })
- ),
- defaultValues: { name: name || "", description: description || "" },
+ const form = useForm({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ name: name || "",
+ description: description || "",
+ githubHandle: githubHandle || "",
+ },
});
- const onSubmit = async (values: { name: string; description?: string }) => {
- await updateProfile.mutateAsync({
- input: {
- name: values.name,
- description: values.description || "",
- siweMessage: "LOGIN_NONCE",
- },
- });
- await queryClient.invalidateQueries({ queryKey: ["profiles"] });
- setOpen(false);
+ const onSubmit = async (values: FormValues) => {
+ try {
+ await updateProfile.mutateAsync({
+ input: {
+ name: values.name,
+ description: values.description || "",
+ github_handle: values.githubHandle || "",
+ siweMessage: "LOGIN_NONCE",
+ },
+ });
+ await queryClient.invalidateQueries({ queryKey: ["profiles"] });
+ setOpen(false);
+ form.reset(values);
+ } catch (error) {
+ console.error("Failed to update profile:", error);
+ }
};
return (
@@ -109,6 +121,25 @@ export function EditProfileDialog({
)}
/>
+ (
+
+ GitHub Handle
+
+
+ @
+
+
+
+
+
+ )}
+ />
);
}
-export default ProfileHeader;
+export default ProfileHeader;
\ No newline at end of file
diff --git a/frontend/src/lib/types/api.d.ts b/frontend/src/lib/types/api.d.ts
index 77b1911..13532a3 100644
--- a/frontend/src/lib/types/api.d.ts
+++ b/frontend/src/lib/types/api.d.ts
@@ -1,14 +1,17 @@
+
export type CreateProfileInput = {
name: string;
description?: string;
avatar_url?: string;
- siweMessage: string; // message to sign for auth
+ github_handle?: string;
+ siweMessage: string;
};
export type UpdateProfileInput = {
name?: string;
description?: string;
avatar_url?: string;
+ github_handle?: string;
siweMessage: string;
};
@@ -21,4 +24,4 @@ export type DeleteProfileInput = {
siweMessage: string;
};
-export type DeleteProfileResponse = unknown;
+export type DeleteProfileResponse = unknown;
\ No newline at end of file
diff --git a/frontend/src/lib/types/profiles.d.ts b/frontend/src/lib/types/profiles.d.ts
index 36e71c7..8f8f3a8 100644
--- a/frontend/src/lib/types/profiles.d.ts
+++ b/frontend/src/lib/types/profiles.d.ts
@@ -18,6 +18,7 @@ export type ProfileFromAPI = {
name?: string;
description?: string;
avatar_url?: string;
+ github_handle?: string;
created_at?: string;
updated_at?: string;
-};
+};
\ No newline at end of file
From bb22529dbc1169f52fa4384e57e45a2bac8e4c8f Mon Sep 17 00:00:00 2001
From: pheobeayo
Date: Tue, 7 Oct 2025 09:46:18 +0100
Subject: [PATCH 2/6] fix changes requested
---
.../action-buttons/EditProfileDialog.tsx | 12 ++++++------
.../profiles/profile-page/ProfileHeader.tsx | 16 +++++-----------
frontend/src/components/ui/GithubIcon.tsx | 16 ++++++++++++++++
frontend/src/lib/types/api.d.ts | 4 ++--
frontend/src/lib/types/profiles.d.ts | 2 +-
5 files changed, 30 insertions(+), 20 deletions(-)
create mode 100644 frontend/src/components/ui/GithubIcon.tsx
diff --git a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
index 9c41ba6..0263b1d 100644
--- a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
+++ b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
@@ -28,7 +28,7 @@ interface EditProfileDialogProps {
address: string;
name?: string;
description?: string;
- githubHandle?: string;
+ githubLogin?: string;
children: React.ReactNode;
}
@@ -37,7 +37,7 @@ const formSchema = z.object({
.string()
.min(2, { message: "Name must be at least 2 characters." }),
description: z.string().optional(),
- githubHandle: z.string().optional(),
+ githubLogin: z.string().optional(),
});
type FormValues = z.infer;
@@ -46,7 +46,7 @@ export function EditProfileDialog({
address,
name,
description,
- githubHandle,
+ githubLogin,
children,
}: EditProfileDialogProps) {
const [open, setOpen] = useState(false);
@@ -58,7 +58,7 @@ export function EditProfileDialog({
defaultValues: {
name: name || "",
description: description || "",
- githubHandle: githubHandle || "",
+ githubLogin: githubLogin || "",
},
});
@@ -68,7 +68,7 @@ export function EditProfileDialog({
input: {
name: values.name,
description: values.description || "",
- github_handle: values.githubHandle || "",
+ github_login: values.githubLogin || "",
siweMessage: "LOGIN_NONCE",
},
});
@@ -123,7 +123,7 @@ export function EditProfileDialog({
/>
(
GitHub Handle
diff --git a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
index 06ec21b..51af304 100644
--- a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
+++ b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
@@ -4,6 +4,7 @@ import { useMemo } from "react";
import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
import AddressTokenBalance from "@/components/AddressTokenBalance";
import CopyAddressToClipboard from "@/components/CopyAddressToClipboard";
+import { GithubIcon } from "@/components/ui/GithubIcon";
export function ProfileHeader({ address }: { address: string }) {
const profilesQuery = useGetProfiles();
@@ -51,23 +52,16 @@ export function ProfileHeader({ address }: { address: string }) {
iconSize="sm"
/>
) : null}
- {profile?.github_handle && (
+ {profile?.github_login && (
)}
diff --git a/frontend/src/components/ui/GithubIcon.tsx b/frontend/src/components/ui/GithubIcon.tsx
new file mode 100644
index 0000000..f1f9840
--- /dev/null
+++ b/frontend/src/components/ui/GithubIcon.tsx
@@ -0,0 +1,16 @@
+interface GithubIconProps {
+ className?: string;
+}
+
+export function GithubIcon({ className = "h-4 w-4" }: GithubIconProps) {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/lib/types/api.d.ts b/frontend/src/lib/types/api.d.ts
index 13532a3..292c658 100644
--- a/frontend/src/lib/types/api.d.ts
+++ b/frontend/src/lib/types/api.d.ts
@@ -3,7 +3,7 @@ export type CreateProfileInput = {
name: string;
description?: string;
avatar_url?: string;
- github_handle?: string;
+ github_login?: string;
siweMessage: string;
};
@@ -11,7 +11,7 @@ export type UpdateProfileInput = {
name?: string;
description?: string;
avatar_url?: string;
- github_handle?: string;
+ github_login?: string;
siweMessage: string;
};
diff --git a/frontend/src/lib/types/profiles.d.ts b/frontend/src/lib/types/profiles.d.ts
index 8f8f3a8..3504fd0 100644
--- a/frontend/src/lib/types/profiles.d.ts
+++ b/frontend/src/lib/types/profiles.d.ts
@@ -18,7 +18,7 @@ export type ProfileFromAPI = {
name?: string;
description?: string;
avatar_url?: string;
- github_handle?: string;
+ github_login?: string;
created_at?: string;
updated_at?: string;
};
\ No newline at end of file
From cedecda79b96d23b7891f3d0abd0dbc39bbad1ea Mon Sep 17 00:00:00 2001
From: pheobeayo
Date: Tue, 7 Oct 2025 13:24:38 +0100
Subject: [PATCH 3/6] fix prefilling
---
.../profiles/action-buttons/EditProfileDialog.tsx | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
index 0263b1d..e9b73a3 100644
--- a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
+++ b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
@@ -22,7 +22,7 @@ import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useUpdateProfile } from "@/hooks/profiles/use-update-profile";
import { useQueryClient } from "@tanstack/react-query";
-import { useState } from "react";
+import { useState, useEffect } from "react";
interface EditProfileDialogProps {
address: string;
@@ -62,6 +62,17 @@ export function EditProfileDialog({
},
});
+
+ useEffect(() => {
+ if (open) {
+ form.reset({
+ name: name || "",
+ description: description || "",
+ githubLogin: githubLogin || "",
+ });
+ }
+ }, [open, name, description, githubLogin, form]);
+
const onSubmit = async (values: FormValues) => {
try {
await updateProfile.mutateAsync({
@@ -74,7 +85,6 @@ export function EditProfileDialog({
});
await queryClient.invalidateQueries({ queryKey: ["profiles"] });
setOpen(false);
- form.reset(values);
} catch (error) {
console.error("Failed to update profile:", error);
}
From f3cd30cd9eb2deaa1e206e40ef319244d14eb96e Mon Sep 17 00:00:00 2001
From: pheobeayo
Date: Tue, 7 Oct 2025 18:20:08 +0100
Subject: [PATCH 4/6] fix props
---
frontend/src/components/pages/ProfilePage.tsx | 29 +++++++++++++++----
.../components/profiles/list/ProfileCard.tsx | 3 ++
.../components/profiles/list/ProfilesList.tsx | 19 ++++++------
.../profiles/profile-page/ProfileActions.tsx | 3 ++
.../src/lib/constants/profileConstants.ts | 7 ++++-
frontend/src/lib/types/profiles.d.ts | 7 +++--
6 files changed, 49 insertions(+), 19 deletions(-)
diff --git a/frontend/src/components/pages/ProfilePage.tsx b/frontend/src/components/pages/ProfilePage.tsx
index bf61232..8018e7b 100644
--- a/frontend/src/components/pages/ProfilePage.tsx
+++ b/frontend/src/components/pages/ProfilePage.tsx
@@ -2,22 +2,41 @@ import { AppWrapper } from "@/components/AppWrapper";
import ProfileHeader from "@/components/profiles/profile-page/ProfileHeader";
import ProfileActions from "@/components/profiles/profile-page/ProfileActions";
import ProfileAttestations from "@/components/profiles/profile-page/ProfileAttestations";
-import ProfileIssuedAttestations from "../profiles/profile-page/ProfileIssuedAttestations";
+import ProfileIssuedAttestations from "@/components/profiles/profile-page/ProfileIssuedAttestations";
+import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
+import { useMemo } from "react";
type Props = { address?: string };
export default function ProfilePage({ address }: Props) {
+ const profilesQuery = useGetProfiles();
+
+ const profile = useMemo(() => {
+ const list = profilesQuery.data ?? [];
+ const p = list.find(
+ (x) => x.address.toLowerCase() === (address || "").toLowerCase()
+ );
+ return p;
+ }, [profilesQuery.data, address]);
+
return (
-
);
-}
+}
\ No newline at end of file
diff --git a/frontend/src/components/profiles/list/ProfileCard.tsx b/frontend/src/components/profiles/list/ProfileCard.tsx
index f3c590a..2a39187 100644
--- a/frontend/src/components/profiles/list/ProfileCard.tsx
+++ b/frontend/src/components/profiles/list/ProfileCard.tsx
@@ -19,6 +19,7 @@ interface ProfileCardProps {
name?: string;
description?: string;
avatar?: string;
+ githubLogin?: string;
attestationCount: number;
attestations: Array<{
id: string;
@@ -33,6 +34,7 @@ export function ProfileCard({
name,
description,
avatar,
+ githubLogin,
attestationCount,
attestations,
}: ProfileCardProps) {
@@ -93,6 +95,7 @@ export function ProfileCard({
address={address}
name={name}
description={description}
+ githubLogin={githubLogin}
>
) : null}
-
{filtered.map((profile) => (
@@ -106,4 +105,4 @@ export function ProfilesList() {
);
}
-export default ProfilesList;
+export default ProfilesList;
\ No newline at end of file
diff --git a/frontend/src/components/profiles/profile-page/ProfileActions.tsx b/frontend/src/components/profiles/profile-page/ProfileActions.tsx
index 69e73fa..3fee851 100644
--- a/frontend/src/components/profiles/profile-page/ProfileActions.tsx
+++ b/frontend/src/components/profiles/profile-page/ProfileActions.tsx
@@ -9,10 +9,12 @@ export function ProfileActions({
address,
name,
description,
+ githubLogin,
}: {
address?: string;
name?: string;
description?: string;
+ githubLogin?: string;
}) {
const { address: connectedAddress } = useAccount();
const isOwner =
@@ -27,6 +29,7 @@ export function ProfileActions({
address={address || ""}
name={name}
description={description}
+ githubLogin={githubLogin}
>