mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
wip adding dashboard, profile and settings page
This commit is contained in:
@@ -131,40 +131,6 @@ async def get_store_agent_details(
|
||||
) from e
|
||||
|
||||
|
||||
async def get_user_profile(
|
||||
user_id: str,
|
||||
) -> backend.server.v2.store.model.ProfileDetails:
|
||||
logger.debug(f"Getting user profile for {user_id}")
|
||||
|
||||
try:
|
||||
profile = await prisma.models.Profile.prisma().find_unique(
|
||||
where={"userId": user_id} # type: ignore
|
||||
)
|
||||
|
||||
if not profile:
|
||||
logger.warning(f"Profile not found for user {user_id}")
|
||||
raise backend.server.v2.store.exceptions.ProfileNotFoundError(
|
||||
f"Profile not found for user {user_id}"
|
||||
)
|
||||
|
||||
return backend.server.v2.store.model.ProfileDetails(
|
||||
name=profile.name,
|
||||
username=profile.username,
|
||||
description=profile.description,
|
||||
links=profile.links,
|
||||
avatar_url=profile.avatarUrl,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting user profile: {str(e)}")
|
||||
return backend.server.v2.store.model.ProfileDetails(
|
||||
name="No Profile Data",
|
||||
username="No Profile Data",
|
||||
description="No Profile Data",
|
||||
links=[],
|
||||
avatar_url="",
|
||||
)
|
||||
|
||||
|
||||
async def get_store_creators(
|
||||
featured: bool = False,
|
||||
search_query: str | None = None,
|
||||
@@ -448,7 +414,41 @@ async def create_store_submission(
|
||||
) from e
|
||||
|
||||
|
||||
async def update_profile(
|
||||
async def get_user_profile(
|
||||
user_id: str,
|
||||
) -> backend.server.v2.store.model.ProfileDetails:
|
||||
logger.debug(f"Getting user profile for {user_id}")
|
||||
|
||||
try:
|
||||
profile = await prisma.models.Profile.prisma().find_unique(
|
||||
where={"userId": user_id} # type: ignore
|
||||
)
|
||||
|
||||
if not profile:
|
||||
logger.warning(f"Profile not found for user {user_id}")
|
||||
raise backend.server.v2.store.exceptions.ProfileNotFoundError(
|
||||
f"Profile not found for user {user_id}"
|
||||
)
|
||||
|
||||
return backend.server.v2.store.model.ProfileDetails(
|
||||
name=profile.name,
|
||||
username=profile.username,
|
||||
description=profile.description,
|
||||
links=profile.links,
|
||||
avatar_url=profile.avatarUrl,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting user profile: {str(e)}")
|
||||
return backend.server.v2.store.model.ProfileDetails(
|
||||
name="No Profile Data",
|
||||
username="No Profile Data",
|
||||
description="No Profile Data",
|
||||
links=[],
|
||||
avatar_url="",
|
||||
)
|
||||
|
||||
|
||||
async def update_or_create_profile(
|
||||
user_id: str, profile: backend.server.v2.store.model.CreatorDetails
|
||||
) -> backend.server.v2.store.model.CreatorDetails:
|
||||
"""
|
||||
@@ -473,7 +473,7 @@ async def update_profile(
|
||||
where={"userId": user_id}
|
||||
)
|
||||
|
||||
# If no profile exists, continue with upsert
|
||||
# If no profile exists, create a new one
|
||||
if not existing_profile:
|
||||
logger.debug(f"Creating new profile for user {user_id}")
|
||||
# Create new profile since one doesn't exist
|
||||
|
||||
@@ -219,7 +219,7 @@ async def test_update_profile(mocker):
|
||||
)
|
||||
|
||||
# Call function
|
||||
result = await db.update_profile("user-id", profile)
|
||||
result = await db.update_or_create_profile("user-id", profile)
|
||||
|
||||
# Verify results
|
||||
assert result.username == "creator"
|
||||
|
||||
@@ -37,6 +37,40 @@ async def get_profile(
|
||||
raise
|
||||
|
||||
|
||||
@router.post(
|
||||
"/profile",
|
||||
tags=["store", "private"],
|
||||
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
|
||||
)
|
||||
async def update_or_create_profile(
|
||||
profile: backend.server.v2.store.model.CreatorDetails,
|
||||
user_id: typing.Annotated[
|
||||
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
|
||||
],
|
||||
) -> backend.server.v2.store.model.CreatorDetails:
|
||||
"""
|
||||
Update the store profile for the authenticated user.
|
||||
|
||||
Args:
|
||||
profile (CreatorDetails): The updated profile details
|
||||
user_id (str): ID of the authenticated user
|
||||
|
||||
Returns:
|
||||
CreatorDetails: The updated profile
|
||||
|
||||
Raises:
|
||||
HTTPException: If there is an error updating the profile
|
||||
"""
|
||||
try:
|
||||
updated_profile = await backend.server.v2.store.db.update_or_create_profile(
|
||||
user_id=user_id, profile=profile
|
||||
)
|
||||
return updated_profile
|
||||
except Exception:
|
||||
logger.exception("Exception occurred whilst updating profile")
|
||||
raise
|
||||
|
||||
|
||||
##############################################
|
||||
############### Agent Endpoints ##############
|
||||
##############################################
|
||||
@@ -315,37 +349,3 @@ async def upload_submission_media(
|
||||
except Exception:
|
||||
logger.exception("Exception occurred whilst uploading submission media")
|
||||
raise
|
||||
|
||||
|
||||
@router.put(
|
||||
"/profile",
|
||||
tags=["store", "private"],
|
||||
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
|
||||
)
|
||||
async def update_profile(
|
||||
profile: backend.server.v2.store.model.CreatorDetails,
|
||||
user_id: typing.Annotated[
|
||||
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
|
||||
],
|
||||
) -> backend.server.v2.store.model.CreatorDetails:
|
||||
"""
|
||||
Update the store profile for the authenticated user.
|
||||
|
||||
Args:
|
||||
profile (CreatorDetails): The updated profile details
|
||||
user_id (str): ID of the authenticated user
|
||||
|
||||
Returns:
|
||||
CreatorDetails: The updated profile
|
||||
|
||||
Raises:
|
||||
HTTPException: If there is an error updating the profile
|
||||
"""
|
||||
try:
|
||||
updated_profile = await backend.server.v2.store.db.update_profile(
|
||||
user_id=user_id, profile=profile
|
||||
)
|
||||
return updated_profile
|
||||
except Exception:
|
||||
logger.exception("Exception occurred whilst updating profile")
|
||||
raise
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Navbar } from "@/components/agptui/Navbar";
|
||||
import { Sidebar } from "@/components/agptui/Sidebar";
|
||||
import { AgentTable } from "@/components/agptui/AgentTable";
|
||||
import { Button } from "@/components/agptui/Button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { IconType } from "@/components/ui/icons";
|
||||
|
||||
interface CreatorDashboardPageProps {
|
||||
isLoggedIn: boolean;
|
||||
userName: string;
|
||||
userEmail: string;
|
||||
navLinks: { name: string; href: string }[];
|
||||
activeLink: string;
|
||||
menuItemGroups: {
|
||||
groupName?: string;
|
||||
items: {
|
||||
icon: IconType;
|
||||
text: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
}[];
|
||||
}[];
|
||||
sidebarLinkGroups: {
|
||||
links: {
|
||||
text: string;
|
||||
href: string;
|
||||
}[];
|
||||
}[];
|
||||
agents: {
|
||||
agentName: string;
|
||||
description: string;
|
||||
imageSrc: string;
|
||||
dateSubmitted: string;
|
||||
status: string;
|
||||
runs: number;
|
||||
rating: number;
|
||||
onEdit: () => void;
|
||||
}[];
|
||||
}
|
||||
|
||||
export default function Page({
|
||||
sidebarLinkGroups,
|
||||
agents,
|
||||
}: CreatorDashboardPageProps) {
|
||||
return (
|
||||
<div className="flex">
|
||||
<Sidebar linkGroups={sidebarLinkGroups} />
|
||||
|
||||
<main className="flex-1 px-6 py-8 md:px-10">
|
||||
{/* Header Section */}
|
||||
<div className="mb-8 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<h1 className="font-neue text-3xl font-medium leading-9 tracking-tight text-neutral-900">
|
||||
Submit a New Agent
|
||||
</h1>
|
||||
<p className="mt-2 font-neue text-sm text-[#707070]">
|
||||
Select from the list of agents you currently have, or upload from
|
||||
your local machine.
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="default" size="lg">
|
||||
Create New Agent
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Separator className="mb-8" />
|
||||
|
||||
{/* Agents Section */}
|
||||
<div>
|
||||
<h2 className="mb-4 text-xl font-bold text-neutral-900">
|
||||
Your Agents
|
||||
</h2>
|
||||
<AgentTable agents={agents} />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as React from "react";
|
||||
import { Sidebar } from "@/components/agptui/Sidebar";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const sidebarLinkGroups = [
|
||||
{
|
||||
links: [
|
||||
{ text: "Creator Dashboard", href: "/store/dashboard" },
|
||||
{ text: "Agent dashboard", href: "/store/agent-dashboard" },
|
||||
{ text: "Integrations", href: "/store/integrations" },
|
||||
{ text: "Profile", href: "/store/profile" },
|
||||
{ text: "Settings", href: "/store/settings" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col lg:flex-row">
|
||||
<Sidebar linkGroups={sidebarLinkGroups} />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import * as React from "react";
|
||||
import { Sidebar } from "@/components/agptui/Sidebar";
|
||||
import { ProfileInfoForm } from "@/components/agptui/ProfileInfoForm";
|
||||
import { IconType } from "@/components/ui/icons";
|
||||
import { Navbar } from "@/components/agptui/Navbar";
|
||||
|
||||
interface ProfilePageProps {
|
||||
userName?: string;
|
||||
userEmail?: string;
|
||||
credits?: number;
|
||||
displayName?: string;
|
||||
handle?: string;
|
||||
bio?: string;
|
||||
links?: Array<{ id: number; url: string }>;
|
||||
categories?: Array<{ id: number; name: string }>;
|
||||
menuItemGroups?: Array<{
|
||||
items: Array<{
|
||||
icon: IconType;
|
||||
text: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
}>;
|
||||
}>;
|
||||
isLoggedIn?: boolean;
|
||||
avatarSrc?: string;
|
||||
}
|
||||
|
||||
const ProfilePage = ({
|
||||
userName = "",
|
||||
userEmail = "",
|
||||
credits = 0,
|
||||
displayName = "",
|
||||
handle = "",
|
||||
bio = "",
|
||||
links = [],
|
||||
categories = [],
|
||||
menuItemGroups = [],
|
||||
isLoggedIn = true,
|
||||
avatarSrc,
|
||||
}: ProfilePageProps) => {
|
||||
const sidebarLinkGroups = [
|
||||
{
|
||||
links: [
|
||||
{ text: "Creator Dashboard", href: "/dashboard" },
|
||||
{ text: "Agent dashboard", href: "/agent-dashboard" },
|
||||
{ text: "Integrations", href: "/integrations" },
|
||||
{ text: "Profile", href: "/profile" },
|
||||
{ text: "Settings", href: "/settings" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const updatedMenuItemGroups = [
|
||||
{
|
||||
items: [
|
||||
{ icon: IconType.Edit, text: "Edit profile", href: "/profile/edit" },
|
||||
],
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{
|
||||
icon: IconType.LayoutDashboard,
|
||||
text: "Creator Dashboard",
|
||||
href: "/dashboard",
|
||||
},
|
||||
{
|
||||
icon: IconType.UploadCloud,
|
||||
text: "Publish an agent",
|
||||
href: "/publish",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
items: [{ icon: IconType.Settings, text: "Settings", href: "/settings" }],
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{
|
||||
icon: IconType.LogOut,
|
||||
text: "Log out",
|
||||
onClick: () => console.log("Logged out"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const navLinks = [
|
||||
{ name: "Marketplace", href: "/marketplace" },
|
||||
{ name: "Library", href: "/library" },
|
||||
{ name: "Build", href: "/build" },
|
||||
];
|
||||
|
||||
return (
|
||||
<ProfileInfoForm
|
||||
displayName={displayName}
|
||||
handle={handle}
|
||||
bio={bio}
|
||||
links={links}
|
||||
categories={categories}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfilePage;
|
||||
@@ -0,0 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { SettingsInputForm } from "@/components/agptui/SettingsInputForm";
|
||||
|
||||
export default function Page() {
|
||||
return <SettingsInputForm />;
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export default async function RootLayout({
|
||||
{
|
||||
icon: IconType.Edit,
|
||||
text: "Edit profile",
|
||||
href: "/profile/edit",
|
||||
href: "/store/profile",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -79,12 +79,12 @@ export default async function RootLayout({
|
||||
{
|
||||
icon: IconType.LayoutDashboard,
|
||||
text: "Creator Dashboard",
|
||||
href: "/dashboard",
|
||||
href: "/store/dashboard",
|
||||
},
|
||||
{
|
||||
icon: IconType.UploadCloud,
|
||||
text: "Publish an agent",
|
||||
href: "/publish",
|
||||
href: "/store/publish",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -93,7 +93,7 @@ export default async function RootLayout({
|
||||
{
|
||||
icon: IconType.Settings,
|
||||
text: "Settings",
|
||||
href: "/settings",
|
||||
href: "/store/settings",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -16,9 +16,9 @@ export function Providers({
|
||||
return (
|
||||
<NextThemesProvider {...props}>
|
||||
<SupabaseProvider initialUser={initialUser}>
|
||||
<CredentialsProvider>
|
||||
<TooltipProvider>{children}</TooltipProvider>
|
||||
</CredentialsProvider>
|
||||
{/* <CredentialsProvider> */}
|
||||
<TooltipProvider>{children}</TooltipProvider>
|
||||
{/* </CredentialsProvider> */}
|
||||
</SupabaseProvider>
|
||||
</NextThemesProvider>
|
||||
);
|
||||
|
||||
@@ -31,7 +31,6 @@ interface NavbarProps {
|
||||
}
|
||||
|
||||
async function getProfileData(user: User | null) {
|
||||
console.log(user);
|
||||
const api = new AutoGPTServerAPIServerSide();
|
||||
const [profile, credits] = await Promise.all([
|
||||
api.getStoreProfile(),
|
||||
@@ -53,8 +52,6 @@ export const Navbar = async ({
|
||||
let profile: ProfileDetails | null = null;
|
||||
let credits: { credits: number } = { credits: 0 };
|
||||
if (isLoggedIn) {
|
||||
console.log("Fetching profile data");
|
||||
console.log(user);
|
||||
const { profile: t_profile, credits: t_credits } =
|
||||
await getProfileData(user);
|
||||
profile = t_profile;
|
||||
|
||||
@@ -10,6 +10,8 @@ export interface ProfileInfoFormProps {
|
||||
profileImage?: string;
|
||||
links: { id: number; url: string }[];
|
||||
categories: { id: number; name: string }[];
|
||||
onCategoryClick: (category: string) => void;
|
||||
selectedCategories: string[];
|
||||
}
|
||||
|
||||
export const AVAILABLE_CATEGORIES = [
|
||||
@@ -24,27 +26,16 @@ export const AVAILABLE_CATEGORIES = [
|
||||
"Research",
|
||||
] as const;
|
||||
|
||||
export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
export const ProfileInfoForm = ({
|
||||
displayName,
|
||||
handle,
|
||||
bio,
|
||||
profileImage,
|
||||
links,
|
||||
categories,
|
||||
}) => {
|
||||
const [selectedCategories, setSelectedCategories] = React.useState<string[]>(
|
||||
categories.map((cat) => cat.name),
|
||||
);
|
||||
|
||||
const handleCategoryClick = (category: string) => {
|
||||
console.log(`${category} category button was pressed`);
|
||||
if (selectedCategories.includes(category)) {
|
||||
setSelectedCategories(selectedCategories.filter((c) => c !== category));
|
||||
} else if (selectedCategories.length < 5) {
|
||||
setSelectedCategories([...selectedCategories, category]);
|
||||
}
|
||||
};
|
||||
|
||||
onCategoryClick,
|
||||
selectedCategories,
|
||||
}: ProfileInfoFormProps) => {
|
||||
return (
|
||||
<main className="p-4 sm:p-8">
|
||||
<h1 className="mb-6 font-['Poppins'] text-[28px] font-medium text-neutral-900 sm:mb-8 sm:text-[35px]">
|
||||
@@ -82,7 +73,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
<div className="rounded-[55px] border border-slate-200 px-4 py-2.5">
|
||||
<input
|
||||
type="text"
|
||||
value={displayName}
|
||||
defaultValue={displayName}
|
||||
placeholder="Enter your display name"
|
||||
className="w-full border-none bg-transparent font-['Inter'] text-base font-normal text-[#666666] focus:outline-none"
|
||||
/>
|
||||
@@ -104,7 +95,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
<div className="rounded-[55px] border border-slate-200 px-4 py-2.5">
|
||||
<input
|
||||
type="text"
|
||||
value={handle}
|
||||
defaultValue={handle}
|
||||
placeholder="@username"
|
||||
className="w-full border-none bg-transparent font-['Inter'] text-base font-normal text-[#666666] focus:outline-none"
|
||||
/>
|
||||
@@ -125,7 +116,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
</label>
|
||||
<div className="h-[220px] rounded-2xl border border-slate-200 py-2.5 pl-4 pr-4">
|
||||
<textarea
|
||||
value={bio}
|
||||
defaultValue={bio}
|
||||
placeholder="Tell us about yourself..."
|
||||
className="h-full w-full resize-none border-none bg-transparent font-['Geist'] text-base font-normal text-[#666666] focus:outline-none"
|
||||
/>
|
||||
@@ -167,7 +158,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
<input
|
||||
type="text"
|
||||
placeholder="https://"
|
||||
value={link?.url || ""}
|
||||
defaultValue={link?.url || ""}
|
||||
className="w-full border-none bg-transparent font-['Inter'] text-base font-normal text-[#666666] focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
@@ -190,7 +181,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
|
||||
<hr className="my-8 border-neutral-300" />
|
||||
|
||||
<section>
|
||||
{/* <section>
|
||||
<div className="relative min-h-[190px] w-full">
|
||||
<div className="absolute left-0 top-0 h-[68px] w-full">
|
||||
<div className="absolute left-0 top-[48px] w-full font-['Geist'] text-base font-medium leading-tight text-slate-950">
|
||||
@@ -205,7 +196,7 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
<Button
|
||||
key={index}
|
||||
variant="outline"
|
||||
onClick={() => handleCategoryClick(category)}
|
||||
onClick={() => onCategoryClick(category)}
|
||||
className={`rounded-[34px] border border-neutral-600 px-5 py-3 transition-colors ${
|
||||
selectedCategories.includes(category)
|
||||
? "bg-slate-900 text-white hover:bg-slate-800"
|
||||
@@ -216,8 +207,8 @@ export const ProfileInfoForm: React.FC<ProfileInfoFormProps> = ({
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div> */}
|
||||
{/* </section> */}
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -36,82 +36,6 @@ interface ProfilePopoutMenuProps {
|
||||
}[];
|
||||
}
|
||||
|
||||
interface PopoutMenuItemProps {
|
||||
icon: IconType;
|
||||
text: React.ReactNode;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const PopoutMenuItem: React.FC<PopoutMenuItemProps> = ({
|
||||
icon,
|
||||
text,
|
||||
href,
|
||||
onClick,
|
||||
}) => {
|
||||
const getIcon = (iconType: IconType) => {
|
||||
let iconClass = "w-6 h-6 relative";
|
||||
const getIconWithAccessibility = (
|
||||
Icon: React.ComponentType<any>,
|
||||
label: string,
|
||||
) => (
|
||||
<Icon className={iconClass} role="img" aria-label={label}>
|
||||
<title>{label}</title>
|
||||
</Icon>
|
||||
);
|
||||
|
||||
switch (iconType) {
|
||||
case IconType.Marketplace:
|
||||
return getIconWithAccessibility(IconMarketplace, "Marketplace");
|
||||
case IconType.Library:
|
||||
return getIconWithAccessibility(IconLibrary, "Library");
|
||||
case IconType.Builder:
|
||||
return getIconWithAccessibility(IconBuilder, "Builder");
|
||||
case IconType.Edit:
|
||||
return getIconWithAccessibility(IconEdit, "Edit");
|
||||
case IconType.LayoutDashboard:
|
||||
return getIconWithAccessibility(IconLayoutDashboard, "Dashboard");
|
||||
case IconType.UploadCloud:
|
||||
return getIconWithAccessibility(IconUploadCloud, "Upload");
|
||||
case IconType.Settings:
|
||||
return getIconWithAccessibility(IconSettings, "Settings");
|
||||
case IconType.LogOut:
|
||||
return getIconWithAccessibility(IconLogOut, "Log Out");
|
||||
default:
|
||||
return getIconWithAccessibility(IconRefresh, "Refresh");
|
||||
}
|
||||
};
|
||||
if (onClick && href) {
|
||||
console.warn("onClick and href are both defined");
|
||||
}
|
||||
const content = (
|
||||
<div className="inline-flex w-full items-center justify-start gap-2.5 hover:rounded hover:bg-[#e0e0e0]">
|
||||
{getIcon(icon)}
|
||||
<div className="font-['Inter'] text-base font-normal leading-7 text-[#474747]">
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (onClick) {
|
||||
return (
|
||||
<div className="w-full" onClick={onClick}>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
<Link href={href} className="w-full">
|
||||
{content}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
export const ProfilePopoutMenu: React.FC<ProfilePopoutMenuProps> = ({
|
||||
userName,
|
||||
userEmail,
|
||||
@@ -120,6 +44,30 @@ export const ProfilePopoutMenu: React.FC<ProfilePopoutMenuProps> = ({
|
||||
}) => {
|
||||
const popupId = React.useId();
|
||||
|
||||
const getIcon = (icon: IconType) => {
|
||||
const iconClass = "w-6 h-6";
|
||||
switch (icon) {
|
||||
case IconType.LayoutDashboard:
|
||||
return <IconLayoutDashboard className={iconClass} />;
|
||||
case IconType.UploadCloud:
|
||||
return <IconUploadCloud className={iconClass} />;
|
||||
case IconType.Edit:
|
||||
return <IconEdit className={iconClass} />;
|
||||
case IconType.Settings:
|
||||
return <IconSettings className={iconClass} />;
|
||||
case IconType.LogOut:
|
||||
return <IconLogOut className={iconClass} />;
|
||||
case IconType.Marketplace:
|
||||
return <IconMarketplace className={iconClass} />;
|
||||
case IconType.Library:
|
||||
return <IconLibrary className={iconClass} />;
|
||||
case IconType.Builder:
|
||||
return <IconBuilder className={iconClass} />;
|
||||
default:
|
||||
return <IconRefresh className={iconClass} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
@@ -168,20 +116,33 @@ export const ProfilePopoutMenu: React.FC<ProfilePopoutMenuProps> = ({
|
||||
key={groupIndex}
|
||||
className="flex w-full flex-col items-start justify-start gap-5 rounded-[18px] bg-white p-3.5"
|
||||
>
|
||||
{group.items.map((item, itemIndex) => (
|
||||
<div
|
||||
key={itemIndex}
|
||||
className="inline-flex w-full items-center justify-start gap-2.5"
|
||||
onClick={item.onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="relative h-6 w-6">{getIcon(item.icon)}</div>
|
||||
<div className="font-['Geist'] text-base font-medium leading-normal text-neutral-800">
|
||||
{item.text}
|
||||
{group.items.map((item, itemIndex) =>
|
||||
item.href ? (
|
||||
<Link
|
||||
key={itemIndex}
|
||||
href={item.href}
|
||||
className="inline-flex w-full items-center justify-start gap-2.5"
|
||||
>
|
||||
<div className="relative h-6 w-6">{getIcon(item.icon)}</div>
|
||||
<div className="font-['Geist'] text-base font-medium leading-normal text-neutral-800">
|
||||
{item.text}
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div
|
||||
key={itemIndex}
|
||||
className="inline-flex w-full items-center justify-start gap-2.5"
|
||||
onClick={item.onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="relative h-6 w-6">{getIcon(item.icon)}</div>
|
||||
<div className="font-['Geist'] text-base font-medium leading-normal text-neutral-800">
|
||||
{item.text}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -189,22 +150,3 @@ export const ProfilePopoutMenu: React.FC<ProfilePopoutMenuProps> = ({
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
// Helper function to get the icon component
|
||||
const getIcon = (icon: IconType) => {
|
||||
const iconClass = "w-6 h-6";
|
||||
switch (icon) {
|
||||
case IconType.LayoutDashboard:
|
||||
return <IconLayoutDashboard className={iconClass} />;
|
||||
case IconType.UploadCloud:
|
||||
return <IconUploadCloud className={iconClass} />;
|
||||
case IconType.Edit:
|
||||
return <IconEdit className={iconClass} />;
|
||||
case IconType.Settings:
|
||||
return <IconSettings className={iconClass} />;
|
||||
case IconType.LogOut:
|
||||
return <IconLogOut className={iconClass} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
@@ -41,12 +41,12 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
<div className="h-full w-full rounded-2xl bg-zinc-200">
|
||||
<div className="inline-flex h-[264px] flex-col items-start justify-start gap-6 p-3">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
href="/store/dashboard"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconDashboardLayout className="h-6 w-6" />
|
||||
<div className="shrink grow basis-0 font-['Inter'] text-base font-medium leading-normal">
|
||||
Agent dashboard
|
||||
Creator dashboard
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
@@ -59,7 +59,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="/profile"
|
||||
href="/store/profile"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconProfile className="h-6 w-6" />
|
||||
@@ -68,7 +68,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="/settings"
|
||||
href="/store/settings"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconSliders className="h-6 w-6" />
|
||||
@@ -85,7 +85,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
<div className="h-full w-full rounded-2xl bg-zinc-200">
|
||||
<div className="inline-flex h-[264px] flex-col items-start justify-start gap-6 p-3">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
href="/store/dashboard"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconDashboardLayout className="h-6 w-6" />
|
||||
@@ -103,7 +103,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="/profile"
|
||||
href="/store/profile"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconProfile className="h-6 w-6" />
|
||||
@@ -112,7 +112,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ linkGroups }) => {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="/settings"
|
||||
href="/store/settings"
|
||||
className="inline-flex items-center justify-center gap-2.5 self-stretch rounded-xl px-7 py-3 text-neutral-800 hover:bg-neutral-800 hover:text-white"
|
||||
>
|
||||
<IconSliders className="h-6 w-6" />
|
||||
|
||||
@@ -336,7 +336,7 @@ export default class BaseAutoGPTServerAPI {
|
||||
(await this.supabaseClient?.auth.getSession())?.data.session
|
||||
?.access_token || "no-token-found";
|
||||
|
||||
console.log("Token for request type: ", method, path, token);
|
||||
console.log("Request: ", method, path);
|
||||
|
||||
let url = this.baseUrl + path;
|
||||
if (method === "GET" && payload) {
|
||||
|
||||
Reference in New Issue
Block a user