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} >
); } -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