diff --git a/frontend/.astro/data-store.json b/frontend/.astro/data-store.json
index b6340ec..9e8a7dc 100644
--- a/frontend/.astro/data-store.json
+++ b/frontend/.astro/data-store.json
@@ -1 +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\"}}}"]
\ No newline at end of file
+[["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\":\"/Users/antoineestienne/GithubRepositories/TheGuildGenesis/frontend/node_modules/.astro/sessions\"}}}"]
\ No newline at end of file
diff --git a/frontend/src/components/AppWrapper.tsx b/frontend/src/components/AppWrapper.tsx
index 4aa2aa7..80a1421 100644
--- a/frontend/src/components/AppWrapper.tsx
+++ b/frontend/src/components/AppWrapper.tsx
@@ -3,7 +3,6 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider } from "wagmi";
import { RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { config } from "../lib/wagmi";
-
import { ConnectButton } from "@rainbow-me/rainbowkit";
import {
SidebarProvider,
@@ -16,18 +15,17 @@ import { AppBackground } from "@/components/AppBackground";
const queryClient = new QueryClient();
-interface Web3ProviderProps {
+interface AppWrapperProps {
children: React.ReactNode;
}
-export function AppWrapper({ children }: Web3ProviderProps) {
+export function AppWrapper({ children }: AppWrapperProps) {
return (
- {/* === Foreground (sidebar, header, main) === */}
@@ -40,7 +38,6 @@ export function AppWrapper({ children }: Web3ProviderProps) {
The Guild Genesis
-
@@ -48,7 +45,6 @@ export function AppWrapper({ children }: Web3ProviderProps) {
-
{children}
diff --git a/frontend/src/components/pages/ProfilePage.tsx b/frontend/src/components/pages/ProfilePage.tsx
index bf61232..2b74efd 100644
--- a/frontend/src/components/pages/ProfilePage.tsx
+++ b/frontend/src/components/pages/ProfilePage.tsx
@@ -1,23 +1,12 @@
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 { ProfileMain } from "@/components/profiles/profile-page/ProfileMain";
type Props = { address?: string };
export default function ProfilePage({ address }: Props) {
return (
-
+
);
}
diff --git a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
index f4619c6..e9b73a3 100644
--- a/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
+++ b/frontend/src/components/profiles/action-buttons/EditProfileDialog.tsx
@@ -22,50 +22,72 @@ 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;
name?: string;
description?: string;
+ githubLogin?: 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(),
+ githubLogin: z.string().optional(),
+});
+
+type FormValues = z.infer;
+
export function EditProfileDialog({
address,
name,
description,
+ githubLogin,
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 || "",
+ githubLogin: githubLogin || "",
+ },
});
- 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);
+
+ 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({
+ input: {
+ name: values.name,
+ description: values.description || "",
+ github_login: values.githubLogin || "",
+ siweMessage: "LOGIN_NONCE",
+ },
+ });
+ await queryClient.invalidateQueries({ queryKey: ["profiles"] });
+ setOpen(false);
+ } catch (error) {
+ console.error("Failed to update profile:", error);
+ }
};
return (
@@ -109,6 +131,25 @@ export function EditProfileDialog({
)}
/>
+ (
+
+ GitHub Handle
+
+
+ @
+
+
+
+
+
+ )}
+ />
-
-
{isLoading || attestations.isLoading ? (
Loading profiles...
) : null}
@@ -89,7 +88,6 @@ export function ProfilesList() {
"An error occurred"}
) : 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}
>
Edit Profile
diff --git a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
index f75916a..61f6f17 100644
--- a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
+++ b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
@@ -1,27 +1,23 @@
import { User } from "lucide-react";
import { useAccount } from "wagmi";
-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();
-
- const profile = useMemo(() => {
- const list = profilesQuery.data ?? [];
- const p = list.find(
- (x) => x.address.toLowerCase() === (address || "").toLowerCase()
- );
- return p;
- }, [profilesQuery.data, address]);
+interface ProfileHeaderProps {
+ address: string;
+ name?: string;
+ description?: string;
+ githubLogin?: string;
+}
- const displayName =
- profile?.name ||
- (address ? `${address.slice(0, 6)}...${address.slice(-4)}` : "Profile");
- const displayAddress = address
- ? `${address.slice(0, 6)}...${address.slice(-4)}`
- : "";
+export function ProfileHeader({
+ address,
+ name,
+ githubLogin,
+}: ProfileHeaderProps) {
+ const displayName = name || (address ? `${address.slice(0, 6)}...${address.slice(-4)}` : "Profile");
+ const displayAddress = address ? `${address.slice(0, 6)}...${address.slice(-4)}` : "";
const { address: connectedAddress } = useAccount();
const isOwner =
@@ -44,17 +40,30 @@ export function ProfileHeader({ address }: { address: string }) {
)}
{displayAddress ? (
-
) : null}
+ {githubLogin && (
+
+ )}
);
}
-export default ProfileHeader;
+export default ProfileHeader;
\ No newline at end of file
diff --git a/frontend/src/components/profiles/profile-page/ProfileMain.tsx b/frontend/src/components/profiles/profile-page/ProfileMain.tsx
new file mode 100644
index 0000000..a7750d6
--- /dev/null
+++ b/frontend/src/components/profiles/profile-page/ProfileMain.tsx
@@ -0,0 +1,39 @@
+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 "@/components/profiles/profile-page/ProfileIssuedAttestations";
+import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
+import { useMemo } from "react";
+
+export function ProfileMain({ address }: { address: string }) {
+ 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 (
+
+ );
+}
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/constants/profileConstants.ts b/frontend/src/lib/constants/profileConstants.ts
index 5ce3729..7a97c26 100644
--- a/frontend/src/lib/constants/profileConstants.ts
+++ b/frontend/src/lib/constants/profileConstants.ts
@@ -5,6 +5,7 @@ export const PROFILES: Profile[] = [
address: "0x1234...5678",
name: "Alice Developer",
description: "Full-stack developer passionate about Web3 and Rust",
+ githubLogin: "alice-dev",
attestationCount: 5,
attestations: [
{
@@ -31,6 +32,7 @@ export const PROFILES: Profile[] = [
address: "0x9876...5432",
name: "Bob Builder",
description: "Smart contract developer and DeFi enthusiast",
+ githubLogin: "bob-builder",
attestationCount: 3,
attestations: [
{
@@ -49,6 +51,9 @@ export const PROFILES: Profile[] = [
},
{
address: "0x5555...7777",
+ name: "",
+ description: "",
+ githubLogin: undefined,
attestationCount: 2,
attestations: [
{
@@ -59,4 +64,4 @@ export const PROFILES: Profile[] = [
},
],
},
-];
+];
\ 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..292c658 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_login?: string;
+ siweMessage: string;
};
export type UpdateProfileInput = {
name?: string;
description?: string;
avatar_url?: string;
+ github_login?: 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..a369af8 100644
--- a/frontend/src/lib/types/profiles.d.ts
+++ b/frontend/src/lib/types/profiles.d.ts
@@ -7,8 +7,9 @@ type ProfileAttestation = {
export type Profile = {
address: string;
- name?: string;
- description?: string;
+ name: string;
+ description: string;
+ githubLogin?: string;
attestationCount: number;
attestations: ProfileAttestation[];
};
@@ -18,6 +19,7 @@ export type ProfileFromAPI = {
name?: string;
description?: string;
avatar_url?: string;
+ github_login?: string;
created_at?: string;
updated_at?: string;
-};
+};
\ No newline at end of file
diff --git a/frontend/src/pages/profiles/[address].astro b/frontend/src/pages/profiles/[address].astro
index 86d3013..1e90df8 100644
--- a/frontend/src/pages/profiles/[address].astro
+++ b/frontend/src/pages/profiles/[address].astro
@@ -1,17 +1,12 @@
---
-import ProfilePage from "@/components/pages/ProfilePage";
import Layout from "@/layouts/Layout.astro";
-
+import ProfilePage from "@/components/pages/ProfilePage";
const { address } = Astro.params;
-
export const prerender = false;
---
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file