Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/.astro/data-store.json
Original file line number Diff line number Diff line change
@@ -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\"}}}"]
[["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\"}}}"]
8 changes: 2 additions & 6 deletions frontend/src/components/AppWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
<div className="relative min-h-screen">
<AppBackground />
{/* === Foreground (sidebar, header, main) === */}
<SidebarProvider>
<AppSidebar />
<SidebarInset>
Expand All @@ -40,15 +38,13 @@ export function AppWrapper({ children }: Web3ProviderProps) {
The Guild Genesis
</h1>
</div>

<div className="flex items-center space-x-4">
<ActivityTokenBalance />
<ConnectButton />
</div>
</div>
</div>
</header>

<main className="relative z-10">{children}</main>
</SidebarInset>
</SidebarProvider>
Expand Down
15 changes: 2 additions & 13 deletions frontend/src/components/pages/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<AppWrapper>
<section className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<ProfileHeader address={address || ""} />

<ProfileActions address={address || ""} />

<ProfileAttestations address={address || ""} />

<ProfileIssuedAttestations address={address || ""} />
</section>
<ProfileMain address={address || ""} />
</AppWrapper>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof formSchema>;

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<FormValues>({
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 (
Expand Down Expand Up @@ -109,6 +131,25 @@ export function EditProfileDialog({
</FormItem>
)}
/>
<FormField
control={form.control}
name="githubLogin"
render={({ field }) => (
<FormItem>
<FormLabel>GitHub Handle</FormLabel>
<FormControl>
<div className="flex items-center gap-2">
<span className="text-sm text-gray-500">@</span>
<Input
placeholder="username"
{...field}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end gap-2 pt-2">
<DialogClose asChild>
<Button type="button" variant="secondary">
Expand All @@ -131,4 +172,4 @@ export function EditProfileDialog({
);
}

export default EditProfileDialog;
export default EditProfileDialog;
3 changes: 3 additions & 0 deletions frontend/src/components/profiles/list/ProfileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface ProfileCardProps {
name?: string;
description?: string;
avatar?: string;
githubLogin?: string;
attestationCount: number;
attestations: Array<{
id: string;
Expand All @@ -33,6 +34,7 @@ export function ProfileCard({
name,
description,
avatar,
githubLogin,
attestationCount,
attestations,
}: ProfileCardProps) {
Expand Down Expand Up @@ -93,6 +95,7 @@ export function ProfileCard({
address={address}
name={name}
description={description}
githubLogin={githubLogin}
>
<Button
variant="ghost"
Expand Down
19 changes: 9 additions & 10 deletions frontend/src/components/profiles/list/ProfilesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ export function ProfilesList() {
const baseProfiles: Profile[] =
data && data.length > 0
? data.map((p) => ({
address: p.address,
name: p.name,
description: p.description,
attestationCount: 0,
attestations: [],
}))
address: p.address,
name: p.name || "",
description: p.description || "",
githubLogin: p.github_login,
attestationCount: 0,
attestations: [],
}))
: PROFILES;

const attestationsByRecipient = useMemo(() => {
Expand Down Expand Up @@ -75,10 +76,8 @@ export function ProfilesList() {
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>

<CreateProfileButton />
</div>

{isLoading || attestations.isLoading ? (
<p className="text-sm text-gray-600">Loading profiles...</p>
) : null}
Expand All @@ -89,14 +88,14 @@ export function ProfilesList() {
"An error occurred"}
</p>
) : null}

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filtered.map((profile) => (
<ProfileCard
key={profile.address}
address={profile.address}
name={profile.name}
description={profile.description}
githubLogin={profile.githubLogin}
attestationCount={profile.attestationCount}
attestations={profile.attestations}
/>
Expand All @@ -106,4 +105,4 @@ export function ProfilesList() {
);
}

export default ProfilesList;
export default ProfilesList;
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -27,6 +29,7 @@ export function ProfileActions({
address={address || ""}
name={name}
description={description}
githubLogin={githubLogin}
>
<Button variant="outline" className="flex items-center gap-2">
<Edit className="h-4 w-4" /> Edit Profile
Expand Down
49 changes: 29 additions & 20 deletions frontend/src/components/profiles/profile-page/ProfileHeader.tsx
Original file line number Diff line number Diff line change
@@ -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 =
Expand All @@ -44,17 +40,30 @@ export function ProfileHeader({ address }: { address: string }) {
)}
</h1>
{displayAddress ? (
<CopyAddressToClipboard
<CopyAddressToClipboard
address={address}
displayAddress={displayAddress}
className="text-sm text-gray-600"
iconSize="sm"
/>
) : null}
{githubLogin && (
<div className="flex items-center gap-1.5 mt-1">
<GithubIcon className="h-4 w-4 text-gray-500" />
<a
href={`https://github.com/${githubLogin}`}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-gray-700 hover:text-indigo-600 hover:underline"
>
@{githubLogin}
</a>
</div>
)}
<AddressTokenBalance address={address as `0x${string}`} />
</div>
</header>
);
}

export default ProfileHeader;
export default ProfileHeader;
Loading
Loading